imported Cortex 2.1.2 source

git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@16643 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Marcus Overhagen 2006-03-08 13:32:19 +00:00
parent 24159a0c7d
commit a0795c6fe3
281 changed files with 73453 additions and 0 deletions

View File

@ -0,0 +1,151 @@
// AddOnHostApp.cpp
#include "AddOnHostApp.h"
#include "AddOnHostProtocol.h"
#include <Alert.h>
#include <Debug.h>
#include <MediaRoster.h>
#include <cstdlib>
#include <cstring>
__USE_CORTEX_NAMESPACE
using namespace addon_host;
// -------------------------------------------------------- //
// *** implementation
// -------------------------------------------------------- //
int main(int argc, char** argv) {
App app;
if(argc < 2 || strcmp(argv[1], "--addon-host") != 0)
{
int32 response = (new BAlert(
"Cortex AddOnHost",
"This program runs in the background, and is started automatically "
"by Cortex when necessary. You probably don't want to start it manually.",
"Continue", "Quit"))->Go();
if(response == 1)
return 0;
}
app.Run();
return 0;
}
App::~App() {}
App::App() :
BApplication(g_appSignature) {}
// -------------------------------------------------------- //
// *** BLooper
// -------------------------------------------------------- //
bool App::QuitRequested() {
return true;
}
// -------------------------------------------------------- //
// *** BHandler
// -------------------------------------------------------- //
void App::MessageReceived(
BMessage* message) {
status_t err;
// message->PrintToStream();
switch(message->what) {
case M_INSTANTIATE: {
// fetch node info
dormant_node_info info;
const void *data;
ssize_t dataSize;
err = message->FindData("info", B_RAW_TYPE, &data, &dataSize);
if(err < B_OK) {
PRINT((
"!!! App::MessageReceived(M_INSTANTIATE):\n"
" missing 'info'\n"));
break;
}
if(dataSize != sizeof(info)) {
PRINT((
"* App::MessageReceived(M_INSTANTIATE):\n"
" warning: 'info' size mismatch\n"));
if(dataSize > ssize_t(sizeof(info)))
dataSize = sizeof(info);
}
memcpy(reinterpret_cast<void *>(&info), data, dataSize);
// attempt to instantiate
BMediaRoster* r = BMediaRoster::Roster();
media_node node;
err = r->InstantiateDormantNode(
info,
&node);
// if(err == B_OK)
// // reference it
// err = r->GetNodeFor(node.node, &node);
// send status
if(err == B_OK) {
BMessage m(M_INSTANTIATE_COMPLETE);
m.AddInt32("node_id", node.node);
message->SendReply(&m);
}
else {
BMessage m(M_INSTANTIATE_FAILED);
m.AddInt32("error", err);
message->SendReply(&m);
}
}
break;
case M_RELEASE: {
// fetch node info
live_node_info info;
const void *data;
ssize_t dataSize;
err = message->FindData("info", B_RAW_TYPE, &data, &dataSize);
if(err < B_OK) {
PRINT((
"!!! App::MessageReceived(M_RELEASE):\n"
" missing 'info'\n"));
break;
}
if(dataSize != sizeof(info)) {
PRINT((
"* App::MessageReceived(M_RELEASE):\n"
" warning: 'info' size mismatch\n"));
if(dataSize > ssize_t(sizeof(info)))
dataSize = sizeof(info);
}
memcpy(reinterpret_cast<void *>(&info), data, dataSize);
// attempt to release
BMediaRoster* r = BMediaRoster::Roster();
media_node node;
err = r->ReleaseNode(info.node);
// send status
if(err == B_OK) {
BMessage m(M_RELEASE_COMPLETE);
m.AddInt32("node_id", info.node.node);
message->SendReply(&m);
}
else {
BMessage m(M_RELEASE_FAILED);
m.AddInt32("error", err);
message->SendReply(&m);
}
}
break;
default:
_inherited::MessageReceived(message);
}
}
// END -- AddOnHostApp.cpp --

View File

@ -0,0 +1,44 @@
// cortex::NodeManager::AddOnHostApp.h
// * PURPOSE
// Definition of (and provisions for communication with)
// a separate BApplication whose single responsibility is
// to launch nodes. NodeManager-launched nodes run in
// another team, helping to lower the likelihood of a
// socially maladjusted young node taking you out.
//
// * HISTORY
// e.moon 6nov99
#ifndef __NodeManager_AddOnHostApp_H__
#define __NodeManager_AddOnHostApp_H__
#include <Application.h>
#include <MediaAddOn.h>
#include <MediaDefs.h>
#include "cortex_defs.h"
__BEGIN_CORTEX_NAMESPACE
namespace addon_host {
class App :
public BApplication {
typedef BApplication _inherited;
public: // *** implementation
~App();
App();
public: // *** BLooper
bool QuitRequested();
public: // *** BHandler
void MessageReceived(
BMessage* message);
private: // implementation
};
}; // addon_host
__END_CORTEX_NAMESPACE
#endif /*__NodeManager_AddOnHostApp_H__*/

Binary file not shown.

View File

@ -0,0 +1,68 @@
NAME= CortexAddOnHost
TYPE= APP
#%{
# @src->@
SRCS= \
AddOnHostApp.cpp \
../support/debug_tools.cpp
RSRCS= AddOnHost_Resource.rsrc
# @<-src@
#%}
LIBS= be media
X86_LIBS= stdc++.r4
PPC_LIBS= mslcpp_4_0
# specify additional paths to directories following the standard
# libXXX.so or libXXX.a naming scheme. You can specify full paths
# or paths relative to the makefile. The paths included may not
# be recursive, so include all of the paths where libraries can
# be found. Directories where source files are found are
# automatically included.
LIBPATHS=
# additional paths to look for system headers
# thes use the form: #include <header>
# source file directories are NOT auto-included here
SYSTEM_INCLUDE_PATHS =
# additional paths to look for local headers
# thes use the form: #include "header"
# source file directories are automatically included
LOCAL_INCLUDE_PATHS = ..
# specify the level of optimization that you desire
# NONE, SOME, FULL
OPTIMIZE= FULL
DEFINES= #DEBUG=1 NDEBUG=0
DEBUGGER = #TRUE
# specify special warning levels
# if unspecified default warnings will be used
# NONE = supress all warnings
# ALL = enable all warnings
WARNINGS = ALL
# specify whether image symbols will be created
# so that stack crawls in the debugger are meaningful
# if TRUE symbols will be created
SYMBOLS =
# if TRUE, all symbols will be removed
STRIP_SYMBOLS = TRUE
# specify additional compiler flags for all files
COMPILER_FLAGS = -DCORTEX_NAMESPACE=cortex
# specify additional linker flags
LINKER_FLAGS =
## include local makefile-engine
include ../makefile-engine

View File

@ -0,0 +1,325 @@
// DiagramBox.cpp
#include "DiagramBox.h"
#include "DiagramDefs.h"
#include "DiagramEndPoint.h"
#include "DiagramView.h"
#include <Message.h>
#include <Messenger.h>
__USE_CORTEX_NAMESPACE
#include <Debug.h>
#define D_METHOD(x) //PRINT (x)
#define D_MESSAGE(x) //PRINT (x)
#define D_MOUSE(x) //PRINT (x)
#define D_DRAW(x) //PRINT (x)
// -------------------------------------------------------- //
// *** ctor/dtor (public)
// -------------------------------------------------------- //
DiagramBox::DiagramBox(
BRect frame,
uint32 flags)
: DiagramItem(DiagramItem::M_BOX),
DiagramItemGroup(DiagramItem::M_ENDPOINT),
m_frame(frame),
m_flags(flags)
{
D_METHOD(("DiagramBox::DiagramBox()\n"));
makeDraggable(true);
}
DiagramBox::~DiagramBox()
{
D_METHOD(("DiagramBox::~DiagramBox()\n"));
}
// -------------------------------------------------------- //
// *** derived from DiagramItemGroup (public)
// -------------------------------------------------------- //
bool DiagramBox::addItem(
DiagramItem *item)
{
D_METHOD(("DiagramBox::addItem()\n"));
if (item)
{
if (DiagramItemGroup::addItem(item))
{
if (m_view)
{
item->_setOwner(m_view);
item->attachedToDiagram();
}
return true;
}
}
return false;
}
bool DiagramBox::removeItem(
DiagramItem *item)
{
D_METHOD(("DiagramBox::removeItem()\n"));
if (item)
{
item->detachedFromDiagram();
if (DiagramItemGroup::removeItem(item))
{
item->_setOwner(0);
return true;
}
}
return false;
}
// -------------------------------------------------------- //
// *** derived from DiagramItem (public)
// -------------------------------------------------------- //
void DiagramBox::draw(
BRect updateRect)
{
D_DRAW(("DiagramBox::draw()\n"));
if (view())
{
view()->PushState();
{
if (m_flags & M_DRAW_UNDER_ENDPOINTS)
{
BRegion region, clipping;
region.Include(frame());
if (group()->getClippingAbove(this, &clipping))
region.Exclude(&clipping);
view()->ConstrainClippingRegion(&region);
drawBox();
for (int32 i = 0; i < countItems(); i++)
{
DiagramItem *item = itemAt(i);
if (region.Intersects(item->frame()))
{
item->draw(item->frame());
}
}
}
else
{
BRegion region, clipping;
region.Include(frame());
if (view()->getClippingAbove(this, &clipping))
region.Exclude(&clipping);
for (int32 i = 0; i < countItems(); i++)
{
DiagramItem *item = itemAt(i);
BRect r;
if (region.Intersects(r = item->frame()))
{
item->draw(r);
region.Exclude(r);
}
}
view()->ConstrainClippingRegion(&region);
drawBox();
}
}
view()->PopState();
}
}
void DiagramBox::mouseDown(
BPoint point,
uint32 buttons,
uint32 clicks)
{
D_MOUSE(("DiagramBox::mouseDown()\n"));
DiagramItem *item = itemUnder(point);
if (item)
{
item->mouseDown(point, buttons, clicks);
}
else if (clicks == 1)
{
if (isSelectable())
{
BMessage selectMsg(M_SELECTION_CHANGED);
if (modifiers() & B_SHIFT_KEY)
{
selectMsg.AddBool("replace", false);
}
else
{
selectMsg.AddBool("replace", true);
}
selectMsg.AddPointer("item", reinterpret_cast<void *>(this));
DiagramView* v = view();
BMessenger(v).SendMessage(&selectMsg);
}
if (isDraggable() && (buttons == B_PRIMARY_MOUSE_BUTTON))
{
BMessage dragMsg(M_BOX_DRAGGED);
dragMsg.AddPointer("item", static_cast<void *>(this));
dragMsg.AddPoint("offset", point - frame().LeftTop());
view()->DragMessage(&dragMsg, BRect(0.0, 0.0, -1.0, -1.0), view());
}
}
}
void DiagramBox::mouseOver(
BPoint point,
uint32 transit)
{
D_MOUSE(("DiagramBox::mouseOver()\n"));
DiagramItem *last = lastItemUnder();
if (last && (transit == B_EXITED_VIEW))
{
last->mouseOver(point, B_EXITED_VIEW);
resetItemUnder();
}
else
{
DiagramItem *item = itemUnder(point);
if (item)
{
if (item != last)
{
if (last)
last->mouseOver(point, B_EXITED_VIEW);
item->mouseOver(point, B_ENTERED_VIEW);
}
else
{
item->mouseOver(point, B_INSIDE_VIEW);
}
}
else if (last)
{
last->mouseOver(point, B_EXITED_VIEW);
}
}
}
void DiagramBox::messageDragged(
BPoint point,
uint32 transit,
const BMessage *message)
{
D_MOUSE(("DiagramBox::messageDragged()\n"));
DiagramItem *last = lastItemUnder();
if (last && (transit == B_EXITED_VIEW))
{
last->messageDragged(point, B_EXITED_VIEW, message);
resetItemUnder();
}
else
{
DiagramItem *item = itemUnder(point);
if (item)
{
if (item != last)
{
if (last)
{
last->messageDragged(point, B_EXITED_VIEW, message);
}
item->messageDragged(point, B_ENTERED_VIEW, message);
}
else
{
item->messageDragged(point, B_INSIDE_VIEW, message);
}
return;
}
else if (last)
{
last->messageDragged(point, B_EXITED_VIEW, message);
}
if (message->what == M_WIRE_DRAGGED)
{
view()->trackWire(point);
}
}
}
void DiagramBox::messageDropped(
BPoint point,
BMessage *message)
{
D_METHOD(("DiagramBox::messageDropped()\n"));
DiagramItem *item = itemUnder(point);
if (item)
{
item->messageDropped(point, message);
return;
}
}
// -------------------------------------------------------- //
// *** operations (public)
// -------------------------------------------------------- //
void DiagramBox::moveBy(
float x,
float y,
BRegion *wireRegion)
{
D_METHOD(("DiagramBox::moveBy()\n"));
if (view())
{
view()->PushState();
{
for (int32 i = 0; i < countItems(); i++)
{
DiagramEndPoint *endPoint = dynamic_cast<DiagramEndPoint *>(itemAt(i));
if (endPoint)
{
endPoint->moveBy(x, y, wireRegion);
}
}
if (wireRegion)
{
wireRegion->Include(m_frame);
m_frame.OffsetBy(x, y);
wireRegion->Include(m_frame);
}
else
{
m_frame.OffsetBy(x, y);
}
}
view()->PopState();
}
}
void DiagramBox::resizeBy(
float horizontal,
float vertical)
{
D_METHOD(("DiagramBox::resizeBy()\n"));
m_frame.right += horizontal;
m_frame.bottom += vertical;
}
// -------------------------------------------------------- //
// *** internal operations (private)
// -------------------------------------------------------- //
void DiagramBox::_setOwner(
DiagramView *owner)
{
D_METHOD(("DiagramBox::_setOwner()\n"));
m_view = owner;
for (int32 i = 0; i < countItems(DiagramItem::M_ENDPOINT); i++)
{
DiagramItem *item = itemAt(i);
item->_setOwner(m_view);
if (m_view)
{
item->attachedToDiagram();
}
}
}
// END -- DiagramBox.cpp --

View File

@ -0,0 +1,130 @@
// DiagramBox.h (Cortex/DiagramView.h)
//
// * PURPOSE
// DiagramItem subclass providing a basic framework for
// boxes in diagrams, i.e. objects that can contain various
// endpoints
//
// * HISTORY
// c.lenz 25sep99 Begun
//
#ifndef __DiagramBox_H__
#define __DiagramBox_H__
#include <Region.h>
#include <Window.h>
#include "DiagramItem.h"
#include "DiagramItemGroup.h"
#include "cortex_defs.h"
__BEGIN_CORTEX_NAMESPACE
class DiagramBox : public DiagramItem,
public DiagramItemGroup
{
public: // *** flags
enum flag_t
{
M_DRAW_UNDER_ENDPOINTS = 0x1
};
public: // *** ctor/dtor
DiagramBox(
BRect frame,
uint32 flags = 0);
virtual ~DiagramBox();
public: // *** hook functions
// is called from draw() to do the actual drawing
virtual void drawBox() = 0;
public: // ** derived from DiagramItemGroup
// extends the DiagramItemGroup implementation by setting
// the items owner and calling the attachedToDiagram() hook
// on it
virtual bool addItem(
DiagramItem *item);
// extends the DiagramItemGroup implementation by calling
// the detachedToDiagram() hook on the item
virtual bool removeItem(
DiagramItem *item);
public: // *** derived from DiagramItem
// returns the Boxes frame rectangle
BRect frame() const
{ return m_frame; }
// prepares the drawing stack and clipping region, then
// calls drawBox
void draw(
BRect updateRect);
// is called from the parent DiagramViews MouseDown() implementation
// if the Box was hit; this version initiates selection and dragging
virtual void mouseDown(
BPoint point,
uint32 buttons,
uint32 clicks);
// is called from the DiagramViews MouseMoved() when no message is being
// dragged, but the mouse has moved above the box
virtual void mouseOver(
BPoint point,
uint32 transit);
// is called from the DiagramViews MouseMoved() when a message is being
// dragged over the DiagramBox
virtual void messageDragged(
BPoint point,
uint32 transit,
const BMessage *message);
// is called from the DiagramViews MessageReceived() function when a
// message has been dropped on the DiagramBox
virtual void messageDropped(
BPoint point,
BMessage *message);
public: // *** operations
// moves the box by a given amount, and returns in updateRegion the
// frames of wires impacted by the move
void moveBy(
float x,
float y,
BRegion *updateRegion);
// resizes the boxes frame without doing any updating
virtual void resizeBy(
float horizontal,
float vertical);
private: // *** internal methods
// is called by the DiagramView when added
void _setOwner(
DiagramView *owner);
private: // *** data
// the boxes' frame rectangle
BRect m_frame;
// flags:
// M_DRAW_UNDER_ENDPOINTS - don't remove EndPoint frames from
// the clipping region
uint32 m_flags;
};
__END_CORTEX_NAMESPACE
#endif /* __DiagramBox_H__ */

View File

@ -0,0 +1,46 @@
// DiagramDefs.h (Cortex/DiagramView)
//
// * PURPOSE
// Contains some global constants used by most of the
// DiagramView classes, currently only message "what"s
//
// * HISTORY
// c.lenz 25sep99 Begun
//
#ifndef __DiagramDefs_H__
#define __DiagramDefs_H__
#include "cortex_defs.h"
__BEGIN_CORTEX_NAMESPACE
// Message constants
enum message_t
{
// Selection changed
// - (DiagramItem *) "item"
// - (bool) "replace"
M_SELECTION_CHANGED = DiagramView_message_base,
// Diagram Box dragged
// - (DiagramBox *) "item"
// - (BPoint) "offset"
M_BOX_DRAGGED,
// Diagram Wire dragged
// - (DiagramEndPoint *) "from"
M_WIRE_DRAGGED,
// Diagram Wire dropped
// - (DiagramEndPoint *) "from"
// - (DiagramEndPoint *) "to"
// - (bool) "success"
M_WIRE_DROPPED,
// Diagram View 'Rect Tracking'
// - (BPoint) "origin"
M_RECT_TRACKING
};
__END_CORTEX_NAMESPACE
#endif /* __DiagramDefs_H__ */

View File

@ -0,0 +1,295 @@
// DiagramEndPoint.cpp
#include "DiagramEndPoint.h"
#include "DiagramDefs.h"
#include "DiagramWire.h"
#include "DiagramView.h"
#include <Message.h>
#include <Messenger.h>
__USE_CORTEX_NAMESPACE
#include <Debug.h>
#define D_METHOD(x) //PRINT (x)
#define D_MESSAGE(x) //PRINT (x)
#define D_MOUSE(x) //PRINT (x)
// -------------------------------------------------------- //
// *** ctor/dtor
// -------------------------------------------------------- //
DiagramEndPoint::DiagramEndPoint(
BRect frame)
: DiagramItem(DiagramItem::M_ENDPOINT),
m_frame(frame),
m_wire(0),
m_connected(false),
m_connecting(false)
{
D_METHOD(("DiagramEndPoint::DiagramEndPoint()\n"));
makeDraggable(true);
}
DiagramEndPoint::~DiagramEndPoint()
{
D_METHOD(("DiagramEndPoint::~DiagramEndPoint()\n"));
}
// -------------------------------------------------------- //
// *** hook functions
// -------------------------------------------------------- //
BPoint DiagramEndPoint::connectionPoint() const
{
D_METHOD(("DiagramEndPoint::connectionPoint()\n"));
return BPoint(frame().left + frame().Height() / 2.0, frame().top + frame().Width() / 2.0);
}
bool DiagramEndPoint::connectionRequested(
DiagramEndPoint *fromWhich)
{
D_METHOD(("DiagramEndPoint::connectionRequested()\n"));
if (!isConnected())
{
return true;
}
return false;
}
// -------------------------------------------------------- //
// *** derived from DiagramItem
// -------------------------------------------------------- //
void DiagramEndPoint::draw(
BRect updateRect)
{
D_METHOD(("DiagramEndPoint::draw()\n"));
if (view())
{
view()->PushState();
{
BRegion region;
region.Include(frame() & updateRect);
view()->ConstrainClippingRegion(&region);
drawEndPoint();
}
view()->PopState();
}
}
void DiagramEndPoint::mouseDown(
BPoint point,
uint32 buttons,
uint32 clicks)
{
D_MOUSE(("DiagramEndPoint::mouseDown()\n"));
if (clicks == 1)
{
if (isSelectable())
{
BMessage selectMsg(M_SELECTION_CHANGED);
if (modifiers() & B_SHIFT_KEY)
{
selectMsg.AddBool("replace", false);
}
else
{
selectMsg.AddBool("replace", true);
}
selectMsg.AddPointer("item", reinterpret_cast<void *>(this));
DiagramView* v = view();
BMessenger(v).SendMessage(&selectMsg);
}
if (isDraggable() && (buttons == B_PRIMARY_MOUSE_BUTTON))
{
BMessage dragMsg(M_WIRE_DRAGGED);
dragMsg.AddPointer("from", static_cast<void *>(this));
view()->DragMessage(&dragMsg, BRect(0.0, 0.0, -1.0, -1.0), view());
view()->messageDragged(point, B_INSIDE_VIEW, &dragMsg);
}
}
}
void DiagramEndPoint::messageDragged(
BPoint point,
uint32 transit,
const BMessage *message)
{
D_MOUSE(("DiagramEndPoint::messageDragged()\n"));
switch (message->what)
{
case M_WIRE_DRAGGED:
{
D_MESSAGE(("DiagramEndPoint::messageDragged(M_WIRE_DRAGGED)\n"));
switch (transit)
{
case B_INSIDE_VIEW:
{
//PRINT((" -> transit: B_INSIDE_VIEW\n"));
// this is a WORK-AROUND caused by the unreliability
// of BViews DragMessage() routine !!
if (isConnecting())
{
break;
}
else if (isConnected())
{
view()->trackWire(point);
}
/* this should be enough in theory:
if (!isConnecting())
{
view()->trackWire(point);
}
//break;*/
}
case B_ENTERED_VIEW:
{
//PRINT((" -> transit: B_ENTERED_VIEW\n"));
DiagramEndPoint *endPoint;
if ((message->FindPointer("from", reinterpret_cast<void **>(&endPoint)) == B_OK)
&& (endPoint != this))
{
if (connectionRequested(endPoint))
{
view()->trackWire(connectionPoint());
if (!isConnecting())
{
m_connecting = true;
connected();
}
}
else
{
view()->trackWire(point);
if (isConnecting())
{
m_connecting = false;
disconnected();
}
}
}
break;
}
case B_EXITED_VIEW:
{
//PRINT((" -> transit: B_EXITED_VIEW\n"));
if (isConnecting())
{
m_connecting = false;
disconnected();
}
break;
}
}
break;
}
default:
{
DiagramItem::messageDragged(point, transit, message);
}
}
}
void DiagramEndPoint::messageDropped(
BPoint point,
BMessage *message)
{
D_MESSAGE(("DiagramEndPoint::messageDropped()\n"));
switch (message->what)
{
case M_WIRE_DRAGGED:
{
D_MESSAGE(("DiagramEndPoint::messageDropped(M_WIRE_DRAGGED)\n"));
DiagramEndPoint *endPoint;
if ((message->FindPointer("from", reinterpret_cast<void **>(&endPoint)) == B_OK)
&& (endPoint != this))
{
bool success = connectionRequested(endPoint);
BMessage dropMsg(M_WIRE_DROPPED);
dropMsg.AddPointer("from", reinterpret_cast<void *>(endPoint));
dropMsg.AddPointer("to", reinterpret_cast<void *>(this));
dropMsg.AddBool("success", success);
DiagramView* v = view();
BMessenger(v).SendMessage(&dropMsg);
if (isConnecting())
{
m_connecting = false;
disconnected();
}
}
return;
}
default:
{
DiagramItem::messageDropped(point, message);
}
}
}
// -------------------------------------------------------- //
// *** frame related operations
// -------------------------------------------------------- //
void DiagramEndPoint::moveBy(
float x,
float y,
BRegion *updateRegion)
{
D_METHOD(("DiagramEndPoint::moveBy()\n"));
if (isConnected() && m_wire && updateRegion)
{
updateRegion->Include(m_wire->frame());
m_frame.OffsetBy(x, y);
m_wire->endPointMoved(this);
updateRegion->Include(m_wire->frame());
}
else
{
m_frame.OffsetBy(x, y);
if (m_wire)
{
m_wire->endPointMoved(this);
}
}
}
void DiagramEndPoint::resizeBy(
float horizontal,
float vertical)
{
D_METHOD(("DiagramEndPoint::resizeBy()\n"));
m_frame.right += horizontal;
m_frame.bottom += vertical;
}
// -------------------------------------------------------- //
// *** connection methods
// -------------------------------------------------------- //
void DiagramEndPoint::connect(
DiagramWire *wire)
{
D_METHOD(("DiagramEndPoint::connect()\n"));
if (!m_connected && wire)
{
m_connected = true;
m_wire = wire;
makeDraggable(false);
connected();
}
}
void DiagramEndPoint::disconnect()
{
D_METHOD(("DiagramEndPoint::disconnect()\n"));
if (m_connected)
{
m_connected = false;
m_wire = 0;
makeDraggable(true);
disconnected();
}
}
// END -- DiagramEndPoint.cpp --

View File

@ -0,0 +1,156 @@
// DiagramItem.h (Cortex/DiagramView)
//
// * PURPOSE
// DiagramItem subclass providing a basic implementation
// of 'connectable' points inside a DiagramBox
//
// * HISTORY
// c.lenz 25sep99 Begun
//
#ifndef __DiagramEndPoint_H__
#define __DiagramEndPoint_H__
#include <Looper.h>
#include <Region.h>
#include "DiagramItem.h"
#include "cortex_defs.h"
__BEGIN_CORTEX_NAMESPACE
class DiagramWire;
class DiagramEndPoint : public DiagramItem
{
public: // *** ctor/dtor
DiagramEndPoint(
BRect frame);
virtual ~DiagramEndPoint();
public: // *** accessors
DiagramWire *wire() const
{ return m_wire; }
public: // *** hook functions
// is called from draw() to do the actual drawing
virtual void drawEndPoint() = 0;
// should return the BPoint that a connected wire uses as
// a drawing offset; this implementation returns the center
// point of the EndPoint
virtual BPoint connectionPoint() const;
// is called from messageDragged() and messageDropped() to
// let you verify that a connection is okay
virtual bool connectionRequested(
DiagramEndPoint *fromWhich);
// is called whenever a connection has been made or a
// temporary wire drag has been accepted
virtual void connected()
{ /* does nothing */ }
// is called whenever a connection has been broken or a
// temporary wire drag has finished
virtual void disconnected()
{ /* does nothing */ }
public: // *** derived from DiagramItem
// returns the EndPoints frame rectangle
BRect frame() const
{ return m_frame; }
// prepares the drawing stack and clipping region, then
// calls drawEndPoint
void draw(
BRect updateRect);
// is called from the parent DiagramBox's mouseDown()
// implementation if the EndPoint was hit; this version
// initiates selection and dragging (i.e. connecting)
virtual void mouseDown(
BPoint point,
uint32 buttons,
uint32 clicks);
// is called from the parent DiagramBox's mouseOver()
// implementation if the mouse is over the EndPoint
virtual void mouseOver(
BPoint point,
uint32 transit)
{ /* does nothing */ }
// is called from the parent DiagramBox's messageDragged()
// implementation of a message is being dragged of the
// EndPoint; this implementation handles only wire drags
// (i.e. M_WIRE_DRAGGED messages)
virtual void messageDragged(
BPoint point,
uint32 transit,
const BMessage *message);
// is called from the parent DiagramBox's messageDropped()
// implementation if the message was dropped on the EndPoint;
// this version handles wire dropping (connecting)
virtual void messageDropped(
BPoint point,
BMessage *message);
// moves the EndPoint by the specified amount and returns in
// updateRegion the frames of connected wires if there are any
// NOTE: no drawing/refreshing is done in this method, that's
// up to the parent
void moveBy(
float x,
float y,
BRegion *updateRegion);
// resize the EndPoints frame rectangle without redraw
virtual void resizeBy(
float horizontal,
float vertical);
public: // *** connection methods
// connect/disconnect and set the wire pointer accordingly
void connect(
DiagramWire *wire);
void disconnect();
// returns true if the EndPoint is currently connected
bool isConnected() const
{ return m_connected; }
// returns true if the EndPoint is currently in a connection
// process (i.e. it is either being dragged somewhere, or a
// M_WIRE_DRAGGED message is being dragged over it
bool isConnecting() const
{ return m_connecting; }
private: // *** data
// the endpoints' frame rectangle
BRect m_frame;
// pointer to the wire object this endpoint might be
// connected to
DiagramWire *m_wire;
// indicates if the endpoint is currently connected
// to another endpoint
bool m_connected;
// indicates that a connection is currently being made
// but has not been confirmed yet
bool m_connecting;
};
__END_CORTEX_NAMESPACE
#endif // __DiagramEndPoint_H__

View File

@ -0,0 +1,118 @@
// DiagramItem.cpp
#include "DiagramItem.h"
#include "DiagramView.h"
__USE_CORTEX_NAMESPACE
#include <Debug.h>
#define D_METHOD(x) //PRINT(x)
// -------------------------------------------------------- //
// *** static member initialization
// -------------------------------------------------------- //
bigtime_t DiagramItem::m_lastSelectionTime = 0;
int32 DiagramItem::m_countSelected = 0;
// -------------------------------------------------------- //
// *** ctor/dtor (public)
// -------------------------------------------------------- //
DiagramItem::DiagramItem(
uint32 itemType)
: m_type(itemType),
m_view(0),
m_group(0),
m_draggable(false),
m_selectable(true),
m_selected(false),
m_selectionTime(system_time())
{
D_METHOD(("DiagramItem::DiagramItem()\n"));
}
DiagramItem::~DiagramItem()
{
D_METHOD(("DiagramItem::~DiagramItem()\n"));
}
// -------------------------------------------------------- //
// *** operations (public)
// -------------------------------------------------------- //
void DiagramItem::select()
{
D_METHOD(("DiagramItem::select()\n"));
if (!m_selected)
{
m_selected = true;
m_lastSelectionTime = m_selectionTime = system_time();
m_countSelected = 1;
selected();
view()->Invalidate(frame());
}
}
void DiagramItem::selectAdding()
{
D_METHOD(("DiagramItem::selectAdding()\n"));
if (!m_selected)
{
m_selected = true;
m_selectionTime = m_lastSelectionTime - m_countSelected++;
selected();
view()->Invalidate(frame());
}
}
void DiagramItem::deselect()
{
D_METHOD(("DiagramItem::deselect()\n"));
if (m_selected)
{
m_selected = false;
deselected();
view()->Invalidate(frame());
}
}
// -------------------------------------------------------- //
// *** hook functions (public)
// -------------------------------------------------------- //
float DiagramItem::howCloseTo(
BPoint point) const
{
D_METHOD(("DiagramItem::howCloseTo()\n"));
if (frame().Contains(point))
{
return 1.0;
}
return 0.0;
}
// -------------------------------------------------------- //
// *** compare functions (friend)
// -------------------------------------------------------- //
int __CORTEX_NAMESPACE__ compareSelectionTime(
const void *lValue,
const void *rValue)
{
D_METHOD(("compareSelectionTime()\n"));
int returnValue = 0;
const DiagramItem *lItem = *(reinterpret_cast<const DiagramItem* const*>(reinterpret_cast<const void* const*>(lValue)));
const DiagramItem *rItem = *(reinterpret_cast<const DiagramItem* const*>(reinterpret_cast<const void* const*>(rValue)));
if (lItem->m_selectionTime < rItem->m_selectionTime)
{
returnValue = 1;
}
else if (lItem->m_selectionTime > rItem->m_selectionTime)
{
returnValue = -1;
}
return returnValue;
}
// END -- DiagramItem.cpp --

View File

@ -0,0 +1,254 @@
// DiagramItem.h (Cortex/DiagramView)
//
// * PURPOSE
// Provides a base class for all items that can be handled
// by the DiagramView implementation. A basic interface with
// some common implementation is defined, with methods related
// to drawing, mouse handling, selecting, dragging, comparison
// for sorting, and access to the drawing context which is the
// DiagramView instance.
//
// * HISTORY
// c.lenz 25sep99 Begun
//
#ifndef __DiagramItem_H__
#define __DiagramItem_H__
#include <OS.h>
#include <InterfaceDefs.h>
#include <Region.h>
class BView;
#include "cortex_defs.h"
__BEGIN_CORTEX_NAMESPACE
class DiagramItemGroup;
class DiagramView;
class DiagramBox;
class DiagramItem
{
friend DiagramItemGroup;
friend DiagramView;
friend DiagramBox;
public: // *** types
enum diagram_item_t {
M_BOX = 0x1,
M_WIRE = 0x2,
M_ENDPOINT = 0x4,
M_ANY = 0x7
};
public: // *** ctor/dtor
DiagramItem(
uint32 itemType);
virtual ~DiagramItem();
public: // *** accessors
// returns the item type assigned in the ctor
uint32 type() const
{ return m_type; }
// returns pointer to the drawing context of the DiagramView
// object
DiagramView *view() const
{ return m_view; }
// returns pointer to the DiagramItemGroup the item belongs to
DiagramItemGroup *group() const
{ return m_group; }
// returns true if the item is currently selected
bool isSelected() const
{ return m_selected; }
public: // *** operations
// changes the selection state of the item, and updates the
// m_selectionTime member in the process to ensure proper
// sorting; calls the selected() hook if the state has
// actually changed
void select();
// sets the item to selected without changing m_selectionTime
// to the time of selection but prior to the last "replacing"
// selection (i.e. thru select()) use this method for additive
// selecting; still calls the selected() hook
void selectAdding();
// deselects the item; calls the deselected() hook if the
// state has actually changed
void deselect();
// moves the items frame to a given point by calling moveBy with the
// absolute coords translated into relative shift amount
void moveTo(
BPoint point,
BRegion *updateRegion = 0)
{ moveBy(point.x - frame().left, point.y - frame().top, updateRegion); }
// resizes the items frame to given dimensions; simply calls the resizeBy
// implementation
void resizeTo(
float width,
float height)
{ resizeBy(width - frame().Width(), height - frame().Height()); }
public: // *** hook functions
// is called when the item has been attached to the DiagramView
// and the view() pointer is valid
virtual void attachedToDiagram()
{ /* does nothing */ }
// is called just before the item is being detached from the
// the DiagramView
virtual void detachedFromDiagram()
{ /* does nothing */ }
// is called from the DiagramViews MouseDown() function after
// finding out the mouse buttons and clicks quantity.
virtual void mouseDown(
BPoint point,
uint32 buttons,
uint32 clicks)
{/* does nothing */}
// is called from the DiagramViews MouseMoved() when *no* message is being
// dragged, i.e. the mouse is simply floating above the item
virtual void mouseOver(
BPoint point,
uint32 transit)
{/* does nothing */}
// is called from the DiagramViews MouseMoved() when a message is being
// dragged; always call the base class version when overriding!
virtual void messageDragged(
BPoint point,
uint32 transit,
const BMessage *message)
{/* does nothing */}
// is called from the DiagramViews MessageReceived() function when an
// message has been received through Drag&Drop; always call the base
// class version when overriding!
virtual void messageDropped(
BPoint point,
BMessage *message)
{/* does nothing */}
// is called when the item has been selected or deselected in some way
virtual void selected()
{ /* does nothing */ }
virtual void deselected()
{ /* does nothing */ }
public: // *** interface definition
// this function must be implemented by derived classes to return the
// items frame rectangle in the DiagramViews coordinates
virtual BRect frame() const = 0;
// this function should be implemented for non-rectangular subclasses
// (like wires) to estimate how close a given point is to the object;
// the default implementation returns 1.0 when the point lies within
// the Frame() rect and 0.0 if not
virtual float howCloseTo(
BPoint point) const;
// this is the hook function called by DiagramView when it's time to
// draw the object
virtual void draw(
BRect updateRect) = 0;
// should move the items frame by the specified amount and do the
// necessary drawing instructions to update the display; if the
// caller supplied a BRegion pointer in updateRegion, this method
// should add other areas affected by the move to it (e.g. wire
// frames)
virtual void moveBy(
float x,
float y,
BRegion *updateRegion = 0)
{ /* does nothing */ }
// should resize the items frame by the specified amount
virtual void resizeBy(
float horizontal,
float vertical)
{ /* does nothing */ }
protected: // *** selecting/dragging
// turn on/off the built-in selection handling
void makeSelectable(
bool selectable)
{ m_selectable = selectable; }
bool isSelectable() const
{ return m_selectable; }
// turn on/off the built-in drag & drop handling
void makeDraggable(
bool draggable)
{ m_draggable = draggable; }
bool isDraggable() const
{ return m_draggable; }
protected: // *** compare functions
// compares the time when each item was last selected and
// returns -1 for the most recent.
friend int compareSelectionTime(
const void *lValue,
const void *rValue);
protected: // *** internal methods
// called only by DiagramItemGroup objects in the method
// addItem()
virtual void _setOwner(
DiagramView *owner)
{ m_view = owner; }
private: // *** data members
// the items type (M_BOX, M_WIRE or M_ENDPOINT)
uint32 m_type;
// a pointer to the drawing context (the DiagramView instance)
DiagramView *m_view;
// a pointer to the DiagramItemGroup the item belongs to
DiagramItemGroup *m_group;
// can the object be dragged
bool m_draggable;
// can the object be selected
bool m_selectable;
// is the object currently selected
bool m_selected;
// when was the object selected the last time or added (used
// for drawing order)
bigtime_t m_selectionTime;
// stores the most recent time a item was selected thru
// the select() method
static bigtime_t m_lastSelectionTime;
// counts the number of selections thru selectAdding()
// since the last call to select()
static int32 m_countSelected;
};
__END_CORTEX_NAMESPACE
#endif /* __DiagramItem_H__ */

View File

@ -0,0 +1,642 @@
// DiagramItemGroup.cpp
#include "DiagramItemGroup.h"
#include "DiagramItem.h"
#include <Region.h>
__USE_CORTEX_NAMESPACE
#include <Debug.h>
#define D_METHOD(x) //PRINT (x)
// -------------------------------------------------------- //
// *** ctor/dtor
// -------------------------------------------------------- //
DiagramItemGroup::DiagramItemGroup(
uint32 acceptedTypes,
bool multiSelection)
: m_boxes(0),
m_wires(0),
m_endPoints(0),
m_selection(0),
m_types(acceptedTypes),
m_itemAlignment(1.0, 1.0),
m_multiSelection(multiSelection),
m_lastItemUnder(0)
{
D_METHOD(("DiagramItemGroup::DiagramItemGroup()\n"));
m_selection = new BList(1);
}
DiagramItemGroup::~DiagramItemGroup()
{
D_METHOD(("DiagramItemGroup::~DiagramItemGroup()\n"));
if (m_selection)
{
m_selection->MakeEmpty();
delete m_selection;
}
if (m_boxes && (m_types & DiagramItem::M_BOX))
{
while (countItems(DiagramItem::M_BOX) > 0)
{
DiagramItem *item = itemAt(0, DiagramItem::M_BOX);
if (removeItem(item))
delete item;
}
delete m_boxes;
}
if (m_wires && (m_types & DiagramItem::M_WIRE))
{
while (countItems(DiagramItem::M_WIRE) > 0)
{
DiagramItem *item = itemAt(0, DiagramItem::M_WIRE);
if (removeItem(item))
delete item;
}
delete m_wires;
}
if (m_endPoints && (m_types & DiagramItem::M_ENDPOINT))
{
while (countItems(DiagramItem::M_ENDPOINT) > 0)
{
DiagramItem *item = itemAt(0, DiagramItem::M_ENDPOINT);
if (removeItem(item))
delete item;
}
delete m_endPoints;
}
}
// -------------------------------------------------------- //
// *** item accessors
// -------------------------------------------------------- //
uint32 DiagramItemGroup::countItems(
uint32 whichType) const
{
D_METHOD(("DiagramItemGroup::countItems()\n"));
uint32 count = 0;
if (whichType & m_types)
{
if (whichType & DiagramItem::M_BOX)
{
if (m_boxes)
{
count += m_boxes->CountItems();
}
}
if (whichType & DiagramItem::M_WIRE)
{
if (m_wires)
{
count += m_wires->CountItems();
}
}
if (whichType & DiagramItem::M_ENDPOINT)
{
if (m_endPoints)
{
count += m_endPoints->CountItems();
}
}
}
return count;
}
DiagramItem *DiagramItemGroup::itemAt(
uint32 index,
uint32 whichType) const
{
D_METHOD(("DiagramItemGroup::itemAt()\n"));
if (m_types & whichType)
{
if (whichType & DiagramItem::M_BOX)
{
if (m_boxes && (index < countItems(DiagramItem::M_BOX)))
{
return static_cast<DiagramItem *>(m_boxes->ItemAt(index));
}
else
{
index -= countItems(DiagramItem::M_BOX);
}
}
if (whichType & DiagramItem::M_WIRE)
{
if (m_wires && (index < countItems(DiagramItem::M_WIRE)))
{
return static_cast<DiagramItem *>(m_wires->ItemAt(index));
}
else
{
index -= countItems(DiagramItem::M_WIRE);
}
}
if (whichType & DiagramItem::M_ENDPOINT)
{
if (m_endPoints && (index < countItems(DiagramItem::M_ENDPOINT)))
{
return static_cast<DiagramItem *>(m_endPoints->ItemAt(index));
}
}
}
return 0;
}
// This function returns the first box or endpoint found that
// contains the given point. For connections it looks at all
// wires that 'might' contain the point and calls their method
// howCloseTo() to find the one closest to the point.
// The lists should be sorted by selection time for proper results!
DiagramItem *DiagramItemGroup::itemUnder(
BPoint point)
{
D_METHOD(("DiagramItemGroup::itemUnder()\n"));
if (m_types & DiagramItem::M_BOX)
{
for (uint32 i = 0; i < countItems(DiagramItem::M_BOX); i++)
{
DiagramItem *item = itemAt(i, DiagramItem::M_BOX);
if (item->frame().Contains(point) && (item->howCloseTo(point) == 1.0))
{
// DiagramItemGroup *group = dynamic_cast<DiagramItemGroup *>(item);
return (m_lastItemUnder = item);
}
}
}
if (m_types & DiagramItem::M_WIRE)
{
float closest = 0.0;
DiagramItem *closestItem = 0;
for (uint32 i = 0; i < countItems(DiagramItem::M_WIRE); i++)
{
DiagramItem *item = itemAt(i, DiagramItem::M_WIRE);
if (item->frame().Contains(point))
{
float howClose = item->howCloseTo(point);
if (howClose > closest)
{
closestItem = item;
if (howClose == 1.0)
return (m_lastItemUnder = item);
closest = howClose;
}
}
}
if (closest > 0.5)
{
return (m_lastItemUnder = closestItem);
}
}
if (m_types & DiagramItem::M_ENDPOINT)
{
for (uint32 i = 0; i < countItems(DiagramItem::M_ENDPOINT); i++)
{
DiagramItem *item = itemAt(i, DiagramItem::M_ENDPOINT);
if (item->frame().Contains(point) && (item->howCloseTo(point) == 1.0))
{
return (m_lastItemUnder = item);
}
}
}
return (m_lastItemUnder = 0); // no item was found!
}
// -------------------------------------------------------- //
// *** item operations
// -------------------------------------------------------- //
bool DiagramItemGroup::addItem(
DiagramItem *item)
{
D_METHOD(("DiagramItemGroup::addItem()\n"));
if (item && (m_types & item->type()))
{
switch (item->type())
{
case DiagramItem::M_BOX:
{
if (!m_boxes)
{
m_boxes = new BList();
}
item->m_group = this;
return m_boxes->AddItem(static_cast<void *>(item));
}
case DiagramItem::M_WIRE:
{
if (!m_wires)
{
m_wires = new BList();
}
item->m_group = this;
return m_wires->AddItem(static_cast<void *>(item));
}
case DiagramItem::M_ENDPOINT:
{
if (!m_endPoints)
{
m_endPoints = new BList();
}
item->m_group = this;
return m_endPoints->AddItem(static_cast<void *>(item));
}
}
}
return false;
}
bool DiagramItemGroup::removeItem(
DiagramItem *item)
{
D_METHOD(("DiagramItemGroup::removeItem()\n"));
if (item && (m_types & item->type()))
{
// reset the lastItemUnder-pointer if it pointed to this item
if (m_lastItemUnder == item)
{
m_lastItemUnder = 0;
}
// remove it from the selection list if it was selected
if (item->isSelected())
{
m_selection->RemoveItem(static_cast<void *>(item));
}
// try to remove the item from its list
switch (item->type())
{
case DiagramItem::M_BOX:
{
if (m_boxes)
{
item->m_group = 0;
return m_boxes->RemoveItem(static_cast<void *>(item));
}
}
case DiagramItem::M_WIRE:
{
if (m_wires)
{
item->m_group = 0;
return m_wires->RemoveItem(static_cast<void *>(item));
}
}
case DiagramItem::M_ENDPOINT:
{
if (m_endPoints)
{
item->m_group = 0;
return m_endPoints->RemoveItem(static_cast<void *>(item));
}
}
}
}
return false;
}
void DiagramItemGroup::sortItems(
uint32 whichType,
int (*compareFunc)(const void *, const void *))
{
D_METHOD(("DiagramItemGroup::sortItems()\n"));
if ((whichType != DiagramItem::M_ANY) && (m_types & whichType))
{
switch (whichType)
{
case DiagramItem::M_BOX:
{
if (m_boxes)
{
m_boxes->SortItems(compareFunc);
}
break;
}
case DiagramItem::M_WIRE:
{
if (m_wires)
{
m_wires->SortItems(compareFunc);
}
break;
}
case DiagramItem::M_ENDPOINT:
{
if (m_endPoints)
{
m_endPoints->SortItems(compareFunc);
}
break;
}
}
}
}
// items are drawn in reverse order; they should be sorted by
// selection time before this function gets called, so that
// the more recently selected item are drawn above others
void DiagramItemGroup::drawItems(
BRect updateRect,
uint32 whichType,
BRegion *updateRegion)
{
D_METHOD(("DiagramItemGroup::drawItems()\n"));
if (whichType & DiagramItem::M_WIRE)
{
for (int32 i = countItems(DiagramItem::M_WIRE) - 1; i >= 0; i--)
{
DiagramItem *item = itemAt(i, DiagramItem::M_WIRE);
if (item->frame().Intersects(updateRect))
{
item->draw(updateRect);
}
}
}
if (whichType & DiagramItem::M_BOX)
{
for (int32 i = countItems(DiagramItem::M_BOX) - 1; i >= 0; i--)
{
DiagramItem *item = itemAt(i, DiagramItem::M_BOX);
if (item && item->frame().Intersects(updateRect))
{
item->draw(updateRect);
if (updateRegion)
updateRegion->Exclude(item->frame());
}
}
}
if (whichType & DiagramItem::M_ENDPOINT)
{
for (int32 i = countItems(DiagramItem::M_ENDPOINT) - 1; i >= 0; i--)
{
DiagramItem *item = itemAt(i, DiagramItem::M_ENDPOINT);
if (item && item->frame().Intersects(updateRect))
{
item->draw(updateRect);
}
}
}
}
bool DiagramItemGroup::getClippingAbove(
DiagramItem *which,
BRegion *region)
{
D_METHOD(("DiagramItemGroup::getClippingAbove()\n"));
bool found = false;
if (which && region)
{
switch (which->type())
{
case DiagramItem::M_BOX:
{
int32 index = m_boxes->IndexOf(which);
if (index >= 0) // the item was found
{
BRect r = which->frame();
for (int32 i = 0; i < index; i++)
{
DiagramItem *item = itemAt(i, DiagramItem::M_BOX);
if (item && item->frame().Intersects(r))
{
region->Include(item->frame() & r);
found = true;
}
}
}
break;
}
case DiagramItem::M_WIRE:
{
BRect r = which->frame();
for (uint32 i = 0; i < countItems(DiagramItem::M_BOX); i++)
{
DiagramItem *item = itemAt(i, DiagramItem::M_BOX);
if (item && item->frame().Intersects(r))
{
region->Include(item->frame() & r);
found = true;
}
}
break;
}
}
}
return found;
}
// -------------------------------------------------------- //
// *** selection accessors
// -------------------------------------------------------- //
uint32 DiagramItemGroup::selectedType() const
{
D_METHOD(("DiagramItemGroup::selectedType()\n"));
if (countSelectedItems() > 0)
{
return selectedItemAt(0)->type();
}
return 0;
}
uint32 DiagramItemGroup::countSelectedItems() const
{
D_METHOD(("DiagramItemGroup::countSelectedItems()\n"));
if (m_selection)
{
return m_selection->CountItems();
}
return 0;
}
DiagramItem *DiagramItemGroup::selectedItemAt(
uint32 index) const
{
D_METHOD(("DiagramItemGroup::selectedItemAt()\n"));
if (m_selection)
{
return static_cast<DiagramItem *>(m_selection->ItemAt(index));
}
return 0;
}
// -------------------------------------------------------- //
// *** selection related operations
// -------------------------------------------------------- //
// selects an item, optionally replacing the complete former
// selection. If the type of the item to be selected differs
// from the type of items currently selected, this methods
// automatically replaces the former selection
bool DiagramItemGroup::selectItem(
DiagramItem *which,
bool deselectOthers)
{
D_METHOD(("DiagramItemGroup::selectItem()\n"));
bool selectionChanged = false;
if (which && !which->isSelected() && which->isSelectable())
{
// check if the item's type is the same as of the other
// selected items
if (m_multiSelection)
{
if (which->type() != selectedType())
{
deselectOthers = true;
}
}
// check if the former selection has to be deselected
if (deselectOthers || !m_multiSelection)
{
while (countSelectedItems() > 0)
{
deselectItem(selectedItemAt(0));
}
}
// select the item
if (deselectOthers || countSelectedItems() == 0)
{
which->select();
}
else
{
which->selectAdding();
}
m_selection->AddItem(which);
selectionChanged = true;
}
// resort the lists if necessary
if (selectionChanged)
{
sortItems(which->type(), compareSelectionTime);
sortSelectedItems(compareSelectionTime);
return true;
}
return false;
}
bool DiagramItemGroup::deselectItem(
DiagramItem *which)
{
D_METHOD(("DiagramItemGroup::deselectItem()\n"));
if (which && which->isSelected())
{
m_selection->RemoveItem(which);
which->deselect();
sortItems(which->type(), compareSelectionTime);
sortSelectedItems(compareSelectionTime);
return true;
}
return false;
}
bool DiagramItemGroup::selectAll(
uint32 itemType)
{
D_METHOD(("DiagramItemGroup::selectAll()\n"));
bool selectionChanged = false;
if (m_types & itemType)
{
for (int32 i = 0; i < countItems(itemType); i++)
{
if (selectItem(itemAt(i, itemType), false))
selectionChanged = true;
}
}
return selectionChanged;
}
bool DiagramItemGroup::deselectAll(
uint32 itemType)
{
D_METHOD(("DiagramItemGroup::deselectAll()\n"));
bool selectionChanged = false;
if (m_types & itemType)
{
for (int32 i = 0; i < countItems(itemType); i++)
{
if (deselectItem(itemAt(i, itemType)))
selectionChanged = true;
}
}
return selectionChanged;
}
void DiagramItemGroup::sortSelectedItems(
int (*compareFunc)(const void *, const void *))
{
D_METHOD(("DiagramItemGroup::sortSelectedItems()\n"));
m_selection->SortItems(compareFunc);
}
void DiagramItemGroup::dragSelectionBy(
float x,
float y,
BRegion *updateRegion)
{
D_METHOD(("DiagramItemGroup::dragSelectionBy()\n"));
if (selectedType() == DiagramItem::M_BOX)
{
align(&x, &y);
if ((x != 0) || (y != 0))
{
for (int32 i = countSelectedItems() - 1; i >= 0; i--)
{
DiagramItem *item = dynamic_cast<DiagramItem *>(selectedItemAt(i));
if (item->isDraggable())
{
item->moveBy(x, y, updateRegion);
}
}
}
}
}
void DiagramItemGroup::removeSelection()
{
D_METHOD(("DiagramItemGroup::removeSelection()\n"));
for (int32 i = 0; i < countSelectedItems(); i++)
{
removeItem(selectedItemAt(i));
}
}
// -------------------------------------------------------- //
// *** alignment related accessors & operations
// -------------------------------------------------------- //
void DiagramItemGroup::getItemAlignment(
float *horizontal,
float *vertical)
{
D_METHOD(("DiagramItemGroup::getItemAlignment()\n"));
if (horizontal)
*horizontal = m_itemAlignment.x;
if (vertical)
*vertical = m_itemAlignment.y;
}
void DiagramItemGroup::align(
float *x,
float *y) const
{
D_METHOD(("DiagramItemGroup::align()\n"));
*x = ((int)*x / (int)m_itemAlignment.x) * m_itemAlignment.x;
*y = ((int)*y / (int)m_itemAlignment.y) * m_itemAlignment.y;
}
BPoint DiagramItemGroup::align(
BPoint point) const
{
D_METHOD(("DiagramItemGroup::align()\n"));
float x = point.x, y = point.y;
align(&x, &y);
return BPoint(x, y);
}
// END -- DiagramItemGroup.cpp --

View File

@ -0,0 +1,203 @@
// DiagramItemGroup.h (Cortex/DiagramView)
//
// * PURPOSE
// Basic class for managing and accessing DiagramItem objects.
// Objects of this class can manage one or more of the DiagramItem
// type M_BOX, M_WIRE and M_ENDPOINT. Many methods let you specify
// which type of item you want to deal with.
//
// * HISTORY
// c.lenz 28sep99 Begun
//
#ifndef __DiagramItemGroup_H__
#define __DiagramItemGroup_H__
#include "DiagramItem.h"
#include <List.h>
#include <Point.h>
#include "cortex_defs.h"
__BEGIN_CORTEX_NAMESPACE
class DiagramItemGroup
{
public: // *** ctor/dtor
DiagramItemGroup(
uint32 acceptedTypes,
bool multiSelection = true);
virtual ~DiagramItemGroup();
public: // *** hook functions
// is called whenever the current selection has changed
virtual void selectionChanged()
{ /*does nothing */ }
public: // *** item accessors
// returns the number of items in the group (optionally only those
// of the given type)
uint32 countItems(
uint32 whichType = DiagramItem::M_ANY) const;
// returns a pointer to the item in the lists which is
// at the given index; if none is found, this function
// returns 0
DiagramItem *itemAt(
uint32 index,
uint32 whichType = DiagramItem::M_ANY) const;
// returns a pointer to the item that is currently under
// the given point, and 0 if there is none
DiagramItem *itemUnder(
BPoint point);
public: // *** item operations
// adds an item to the group; returns true on success
virtual bool addItem(
DiagramItem *item);
// removes an item from the group; returns true on success
bool removeItem(
DiagramItem *item);
// performs a quicksort on a list of items with the provided
// compare function (one is already defined in the DiagramItem
// implementation); can't handle more than one item type at a
// time!
void sortItems(
uint32 itemType,
int (*compareFunc)(const void *, const void *));
// fires a draw() command at all items of a specific type that
// intersect with the updateRect
void drawItems(
BRect updateRect,
uint32 whichType = DiagramItem::M_ANY,
BRegion *updateRegion = 0);
// returns in outRegion the region of items that lay "over" the given
// DiagramItem in which; returns false if no items are above or the item
// doesn't exist
bool getClippingAbove(
DiagramItem *which,
BRegion *outRegion);
public: // *** selection accessors
// returns the type of DiagramItems in the current selection
// (currently only one type at a time is supported!)
uint32 selectedType() const;
// returns the number of items in the current selection
uint32 countSelectedItems() const;
// returns a pointer to the item in the list which is
// at the given index; if none is found, this function
// returns 0
DiagramItem *selectedItemAt(
uint32 index) const;
// returns the ability of the group to handle multiple selections
// as set in the constructor
bool multipleSelection() const
{ return m_multiSelection; }
public: // *** selection related operations
// selects the given item and optionally deselects all others
// (thereby replacing the former selection)
bool selectItem(
DiagramItem *which,
bool deselectOthers = true);
// simply deselects one item
bool deselectItem(
DiagramItem *which);
// performs a quicksort on the list of selected items with the
// provided compare function (one is already defined in the DiagramItem
// implementation)
void sortSelectedItems(
int (*compareFunc)(const void *, const void *));
// select all items of the given type
bool selectAll(
uint32 itemType = DiagramItem::M_ANY);
// deselect all items of the given type
bool deselectAll(
uint32 itemType = DiagramItem::M_ANY);
// moves all selected items by a given amount, taking
// item alignment into account; in updateRegion the areas
// that still require updating by the caller are returned
void dragSelectionBy(
float x,
float y,
BRegion *updateRegion);
// removes all selected items from the group
void removeSelection();
public: // *** alignment related
// set/get the 'item alignment' grid size; this is used when
// items are being dragged and inserted
void setItemAlignment(
float horizontal,
float vertical)
{ m_itemAlignment.Set(horizontal, vertical); }
void getItemAlignment(
float *horizontal,
float *vertical);
// align a given point to the current grid
void align(
float *x,
float *y) const;
BPoint align(
BPoint point) const;
protected: // *** accessors
// returns a pointer to the last item returned by the itemUnder()
// function; this can be used by deriving classes to implement a
// transit system
DiagramItem *lastItemUnder()
{ return m_lastItemUnder; }
void resetItemUnder()
{ m_lastItemUnder = 0; }
private: // *** data members
// pointers to the item-lists (one list for each item type)
BList *m_boxes;
BList *m_wires;
BList *m_endPoints;
// pointer to the list containing the current selection
BList *m_selection;
// the DiagramItem type(s) of items this group will accept
uint32 m_types;
// specifies the "grid"-size for the frames of items
BPoint m_itemAlignment;
// can multiple items be selected at once ?
bool m_multiSelection;
// cached pointer to the item that was found in itemUnder()
DiagramItem *m_lastItemUnder;
};
__END_CORTEX_NAMESPACE
#endif /* __DiagramItemGroup_H__ */

View File

@ -0,0 +1,761 @@
// DiagramView.cpp
#include "DiagramView.h"
#include "DiagramDefs.h"
#include "DiagramBox.h"
#include "DiagramEndPoint.h"
#include "DiagramWire.h"
#include <Bitmap.h>
#include <Message.h>
#include <ScrollBar.h>
__USE_CORTEX_NAMESPACE
#include <Debug.h>
#define D_METHOD(x) //PRINT (x)
#define D_HOOK(x) //PRINT (x)
#define D_MESSAGE(x) //PRINT (x)
#define D_MOUSE(x) //PRINT (x)
#define D_DRAW(x) //PRINT (x)
// -------------------------------------------------------- //
// *** ctor/dtor
// -------------------------------------------------------- //
DiagramView::DiagramView(
BRect frame,
const char *name,
bool multiSelection,
uint32 resizingMode,
uint32 flags)
: BView(frame, name, resizingMode, B_WILL_DRAW | B_FRAME_EVENTS | flags),
DiagramItemGroup(DiagramItem::M_BOX | DiagramItem::M_WIRE),
m_lastButton(0),
m_clickCount(0),
m_lastClickPoint(-1.0, -1.0),
m_pressedButton(0),
m_draggedWire(0),
m_useBackgroundBitmap(false),
m_backgroundBitmap(0)
{
D_METHOD(("DiagramView::DiagramView()\n"));
SetViewColor(B_TRANSPARENT_COLOR);
m_dataRect = Bounds();
}
DiagramView::~DiagramView()
{
D_METHOD(("DiagramView::~DiagramView()\n"));
}
// -------------------------------------------------------- //
// *** hook functions
// -------------------------------------------------------- //
void DiagramView::messageDragged(
BPoint point,
uint32 transit,
const BMessage *message)
{
D_METHOD(("DiagramView::messageDragged()\n"));
switch (message->what)
{
case M_WIRE_DRAGGED:
{
D_MESSAGE(("DiagramView::messageDragged(M_WIRE_DROPPED)\n"));
if (!m_draggedWire)
{
DiagramEndPoint *fromEndPoint;
if (message->FindPointer("from", reinterpret_cast<void **>(&fromEndPoint)) == B_OK)
{
_beginWireTracking(fromEndPoint);
}
}
trackWire(point);
break;
}
}
}
void DiagramView::messageDropped(
BPoint point,
BMessage *message)
{
D_METHOD(("DiagramView::messageDropped()\n"));
switch (message->what)
{
case M_WIRE_DRAGGED:
{
D_MESSAGE(("DiagramView::messageDropped(M_WIRE_DROPPED)\n"));
DiagramEndPoint *fromWhich = 0;
if (message->FindPointer("from", reinterpret_cast<void **>(&fromWhich)) == B_OK)
{
connectionAborted(fromWhich);
}
break;
}
}
}
// -------------------------------------------------------- //
// *** derived from BView
// -------------------------------------------------------- //
// initial scrollbar update [e.moon 16nov99]
void DiagramView::AttachedToWindow()
{
D_METHOD(("DiagramView::AttachedToWindow()\n"));
_updateScrollBars();
}
void DiagramView::Draw(
BRect updateRect)
{
D_METHOD(("DiagramView::Draw()\n"));
drawBackground(updateRect);
drawItems(updateRect, DiagramItem::M_WIRE);
drawItems(updateRect, DiagramItem::M_BOX);
}
void DiagramView::FrameResized(
float width,
float height)
{
D_METHOD(("DiagramView::FrameResized()\n"));
_updateScrollBars();
}
void DiagramView::GetPreferredSize(
float *width,
float *height) {
D_HOOK(("DiagramView::GetPreferredSize()\n"));
*width = m_dataRect.Width() + 10.0;
*height = m_dataRect.Height() + 10.0;
}
void DiagramView::MessageReceived(
BMessage *message)
{
D_METHOD(("DiagramView::MessageReceived()\n"));
switch (message->what)
{
case M_SELECTION_CHANGED:
{
D_MESSAGE(("DiagramView::MessageReceived(M_SELECTION_CHANGED)\n"));
DiagramItem *item;
if (message->FindPointer("item", reinterpret_cast<void **>(&item)) == B_OK)
{
bool deselectOthers = true;
message->FindBool("replace", &deselectOthers);
if (item->isSelected() && !deselectOthers && multipleSelection())
{
if (deselectItem(item))
{
selectionChanged();
}
}
else if (selectItem(item, deselectOthers))
{
sortItems(item->type(), &compareSelectionTime);
selectionChanged();
}
}
break;
}
case M_WIRE_DROPPED:
{
D_MESSAGE(("DiagramView::MessageReceived(M_WIRE_DROPPED)\n"));
DiagramEndPoint *fromWhich = 0;
DiagramEndPoint *toWhich = 0;
bool success = false;
if (message->FindPointer("from", reinterpret_cast<void **>(&fromWhich)) == B_OK)
{
if ((message->FindPointer("to", reinterpret_cast<void **>(&toWhich)) == B_OK)
&& (message->FindBool("success", &success) == B_OK))
{
if (success && fromWhich && toWhich)
{
_endWireTracking();
DiagramWire *wire = createWire(fromWhich, toWhich);
if (wire && addItem(wire))
{
connectionEstablished(fromWhich, toWhich);
break;
}
}
}
}
connectionAborted(fromWhich);
break;
}
default:
{
if (message->WasDropped())
{
BPoint point = ConvertFromScreen(message->DropPoint());
DiagramItem *item = itemUnder(point);
if (item)
{
item->messageDropped(point, message);
return;
}
else
{
messageDropped(point, message);
}
}
else
{
BView::MessageReceived(message);
}
}
}
}
void DiagramView::KeyDown(
const char *bytes,
int32 numBytes)
{
D_METHOD(("DiagramView::KeyDown()\n"));
switch (bytes[0])
{
case B_LEFT_ARROW:
{
float x;
getItemAlignment(&x, 0);
BRegion updateRegion;
dragSelectionBy(-x, 0.0, &updateRegion);
for (int32 i = 0; i < updateRegion.CountRects(); i++)
Invalidate(updateRegion.RectAt(i));
updateDataRect();
break;
}
case B_RIGHT_ARROW:
{
float x;
getItemAlignment(&x, 0);
BRegion updateRegion;
dragSelectionBy(x, 0.0, &updateRegion);
for (int32 i = 0; i < updateRegion.CountRects(); i++)
Invalidate(updateRegion.RectAt(i));
updateDataRect();
break;
}
case B_UP_ARROW:
{
float y;
getItemAlignment(0, &y);
BRegion updateRegion;
dragSelectionBy(0.0, -y, &updateRegion);
for (int32 i = 0; i < updateRegion.CountRects(); i++)
Invalidate(updateRegion.RectAt(i));
updateDataRect();
break;
}
case B_DOWN_ARROW:
{
float y;
getItemAlignment(0, &y);
BRegion updateRegion;
dragSelectionBy(0.0, y, &updateRegion);
for (int32 i = 0; i < updateRegion.CountRects(); i++)
Invalidate(updateRegion.RectAt(i));
updateDataRect();
break;
}
default:
{
BView::KeyDown(bytes, numBytes);
break;
}
}
}
void DiagramView::MouseDown(
BPoint point)
{
D_METHOD(("DiagramView::MouseDown()\n"));
SetMouseEventMask(B_POINTER_EVENTS, B_LOCK_WINDOW_FOCUS | B_NO_POINTER_HISTORY);
// update click count
BMessage* message = Window()->CurrentMessage();
int32 clicks = message->FindInt32("clicks");
int32 buttons = message->FindInt32("buttons");
bool moved = (fabs(point.x - m_lastClickPoint.x) > 2.0 || fabs(point.y - m_lastClickPoint.y) > 2.0);
if (!moved && (buttons == m_lastButton) && (clicks > 1))
{
m_clickCount++;
}
else
{
m_clickCount = 1;
}
m_lastButton = buttons;
m_lastClickPoint = point;
m_lastDragPoint = ConvertToScreen(point);
// [e.moon 16nov99] scroll on 3rd button
m_pressedButton = buttons;
if(m_pressedButton == B_TERTIARY_MOUSE_BUTTON) {
return;
}
// was an item clicked ?
DiagramItem *item = itemUnder(point);
if (item)
{
item->mouseDown(point, m_lastButton, m_clickCount);
}
else // no, the background was clicked
{
if (!(modifiers() & B_SHIFT_KEY) && deselectAll(DiagramItem::M_ANY))
selectionChanged();
if (multipleSelection() && (m_lastButton == B_PRIMARY_MOUSE_BUTTON) && !(modifiers() & B_CONTROL_KEY))
_beginRectTracking(point);
mouseDown(point, m_lastButton, m_clickCount);
}
}
void DiagramView::MouseMoved(
BPoint point,
uint32 transit,
const BMessage *message)
{
D_METHOD(("DiagramView::MouseMoved()\n"));
// [e.moon 16nov99] 3rd-button scrolling
if(m_pressedButton == B_TERTIARY_MOUSE_BUTTON) {
// fetch/store screen point; calculate distance travelled
ConvertToScreen(&point);
float xDelta = m_lastDragPoint.x - point.x;
float yDelta = m_lastDragPoint.y - point.y;
m_lastDragPoint = point;
// constrain to scrollbar limits
BScrollBar* hScroll = ScrollBar(B_HORIZONTAL);
if(xDelta && hScroll) {
float val = hScroll->Value();
float min, max;
hScroll->GetRange(&min, &max);
if(val + xDelta < min)
xDelta = 0;
if(val + xDelta > max)
xDelta = 0;
}
BScrollBar* vScroll = ScrollBar(B_VERTICAL);
if(yDelta && vScroll) {
float val = vScroll->Value();
float min, max;
vScroll->GetRange(&min, &max);
if(val + yDelta < min)
yDelta = 0;
if(val + yDelta > max)
yDelta = 0;
}
// scroll
if(xDelta == 0.0 && yDelta == 0.0)
return;
ScrollBy(xDelta, yDelta);
return;
}
if (message)
{
switch (message->what)
{
case M_RECT_TRACKING:
{
BPoint origin;
if (message->FindPoint("origin", &origin) == B_OK)
{
_trackRect(origin, point);
}
break;
}
case M_BOX_DRAGGED:
{
DiagramBox *box;
BPoint offset;
if ((message->FindPointer("item", reinterpret_cast<void **>(&box)) == B_OK)
&& (message->FindPoint("offset", &offset) == B_OK))
{
if (box)
{
BRegion updateRegion;
dragSelectionBy(point.x - box->frame().left - offset.x,
point.y - box->frame().top - offset.y,
&updateRegion);
updateDataRect();
for (int32 i = 0; i < updateRegion.CountRects(); i++)
{
Invalidate(updateRegion.RectAt(i));
}
}
}
break;
}
default: // unkwown message -> redirect to messageDragged()
{
DiagramItem *last = lastItemUnder();
if (transit == B_EXITED_VIEW)
{
if (last)
{
last->messageDragged(point, B_EXITED_VIEW, message);
messageDragged(point, B_EXITED_VIEW, message);
}
}
else
{
DiagramItem *item = itemUnder(point);
if (item)
{
if (item != last)
{
if (last)
last->messageDragged(point, B_EXITED_VIEW, message);
item->messageDragged(point, B_ENTERED_VIEW, message);
}
else
{
item->messageDragged(point, B_INSIDE_VIEW, message);
}
}
else if (last)
{
last->messageDragged(point, B_EXITED_VIEW, message);
messageDragged(point, B_ENTERED_VIEW, message);
}
else
{
messageDragged(point, transit, message);
}
}
break;
}
}
}
else // no message at all -> redirect to mouseOver()
{
DiagramItem *last = lastItemUnder();
if ((transit == B_EXITED_VIEW) || (transit == B_OUTSIDE_VIEW))
{
if (last)
{
last->mouseOver(point, B_EXITED_VIEW);
resetItemUnder();
mouseOver(point, B_EXITED_VIEW);
}
}
else
{
DiagramItem *item = itemUnder(point);
if (item)
{
if (item != last)
{
if (last)
last->mouseOver(point, B_EXITED_VIEW);
item->mouseOver(point, B_ENTERED_VIEW);
}
else
{
item->mouseOver(point, B_INSIDE_VIEW);
}
}
else if (last)
{
last->mouseOver(point, B_EXITED_VIEW);
mouseOver(point, B_ENTERED_VIEW);
}
}
}
}
void DiagramView::MouseUp(
BPoint point)
{
D_METHOD(("DiagramView::MouseUp()\n"));
if (multipleSelection())
EndRectTracking();
_endWireTracking();
// [e.moon 16nov99] mark no button as down
m_pressedButton = 0;
}
// -------------------------------------------------------- //
// *** derived from DiagramItemGroup (public)
// -------------------------------------------------------- //
bool DiagramView::addItem(
DiagramItem *item)
{
D_METHOD(("DiagramBox::addItem()\n"));
if (item)
{
if (DiagramItemGroup::addItem(item))
{
item->_setOwner(this);
item->attachedToDiagram();
if (item->type() == DiagramItem::M_BOX)
{
updateDataRect();
}
return true;
}
}
return false;
}
bool DiagramView::removeItem(
DiagramItem *item)
{
D_METHOD(("DiagramBox::removeItem()\n"));
if (item)
{
item->detachedFromDiagram();
if (DiagramItemGroup::removeItem(item))
{
item->_setOwner(0);
if (item->type() == DiagramItem::M_BOX)
{
updateDataRect();
}
return true;
}
}
return false;
}
// -------------------------------------------------------- //
// *** operations (public)
// -------------------------------------------------------- //
void DiagramView::trackWire(
BPoint point)
{
D_MOUSE(("DiagramView::trackWire()\n"));
if (m_draggedWire)
{
BRegion region;
region.Include(m_draggedWire->frame());
m_draggedWire->m_dragEndPoint = point;
m_draggedWire->endPointMoved();
region.Include(m_draggedWire->frame());
region.Exclude(&m_boxRegion);
for (int32 i = 0; i < region.CountRects(); i++)
{
Invalidate(region.RectAt(i));
}
}
}
// -------------------------------------------------------- //
// *** internal operations (protected)
// -------------------------------------------------------- //
void DiagramView::drawBackground(
BRect updateRect)
{
D_METHOD(("DiagramView::drawBackground()\n"));
if (m_useBackgroundBitmap)
{
BRegion region;
region.Include(updateRect);
region.Exclude(&m_boxRegion);
BRect bounds = Bounds();
PushState();
{
ConstrainClippingRegion(&region);
for (float y = 0; y < bounds.bottom; y += m_backgroundBitmap->Bounds().Height())
{
for (float x = 0; x < bounds.right; x += m_backgroundBitmap->Bounds().Width())
{
DrawBitmapAsync(m_backgroundBitmap, BPoint(x, y));
}
}
}
PopState();
}
else
{
BRegion region;
region.Include(updateRect);
region.Exclude(&m_boxRegion);
PushState();
{
SetLowColor(m_backgroundColor);
FillRegion(&region, B_SOLID_LOW);
}
PopState();
}
}
void DiagramView::setBackgroundColor(
rgb_color color)
{
D_METHOD(("DiagramView::setBackgroundColor()\n"));
m_backgroundColor = color;
m_useBackgroundBitmap = false;
}
void DiagramView::setBackgroundBitmap(
BBitmap *bitmap)
{
D_METHOD(("DiagramView::setBackgroundBitmap()\n"));
if (m_backgroundBitmap)
{
delete m_backgroundBitmap;
}
m_backgroundBitmap = new BBitmap(bitmap);
m_useBackgroundBitmap = true;
}
void DiagramView::updateDataRect()
{
D_METHOD(("DiagramView::updateDataRect()\n"));
// calculate the area in which boxes display
m_boxRegion.MakeEmpty();
for (int32 i = 0; i < countItems(DiagramItem::M_BOX); i++)
{
m_boxRegion.Include(itemAt(i, DiagramItem::M_BOX)->frame());
}
// adapt the data rect to the new region of boxes
BRect boxRect = m_boxRegion.Frame();
m_dataRect.right = boxRect.right;
m_dataRect.bottom = boxRect.bottom;
// update the scroll bars
_updateScrollBars();
}
// -------------------------------------------------------- //
// *** internal operations (private)
// -------------------------------------------------------- //
void DiagramView::_beginWireTracking(
DiagramEndPoint *startPoint)
{
D_METHOD(("DiagramView::beginWireTracking()\n"));
m_draggedWire = createWire(startPoint);
addItem(m_draggedWire);
selectItem(m_draggedWire, true);
Invalidate(startPoint->frame());
}
void DiagramView::_endWireTracking()
{
D_METHOD(("DiagramView::endWireTracking()\n"));
if (m_draggedWire)
{
removeItem(m_draggedWire);
Invalidate(m_draggedWire->frame());
DiagramEndPoint *endPoint = m_draggedWire->startPoint();
if (!endPoint)
{
endPoint = m_draggedWire->endPoint();
}
if (endPoint)
{
Invalidate(endPoint->frame());
}
delete m_draggedWire;
m_draggedWire = 0;
}
}
void DiagramView::_beginRectTracking(
BPoint origin)
{
D_METHOD(("DiagramView::beginRectTracking()\n"));
BMessage message(M_RECT_TRACKING);
message.AddPoint("origin", origin);
DragMessage(&message, BRect(0.0, 0.0, -1.0, -1.0));
BView::BeginRectTracking(BRect(origin, origin), B_TRACK_RECT_CORNER);
}
void DiagramView::_trackRect(
BPoint origin,
BPoint current)
{
D_METHOD(("DiagramView::trackRect()\n"));
bool changed = false;
BRect rect;
rect.left = origin.x < current.x ? origin.x : current.x;
rect.top = origin.y < current.y ? origin.y : current.y;
rect.right = origin.x < current.x ? current.x : origin.x;
rect.bottom = origin.y < current.y ? current.y : origin.y;
for (int32 i = 0; i < countItems(DiagramItem::M_BOX); i++)
{
DiagramBox *box = dynamic_cast<DiagramBox *>(itemAt(i, DiagramItem::M_BOX));
if (box)
{
if (rect.Intersects(box->frame()))
{
changed |= selectItem(box, false);
}
else
{
changed |= deselectItem(box);
}
}
}
if (changed)
{
sortItems(DiagramItem::M_BOX, &compareSelectionTime);
selectionChanged();
}
}
void DiagramView::_updateScrollBars()
{
D_METHOD(("DiagramView::_updateScrollBars()\n"));
// fetch the vertical ScrollBar
BScrollBar *scrollBar = ScrollBar(B_VERTICAL);
if (scrollBar)
{
// Disable the ScrollBar if the view is large enough to display
// the entire data-rect
if (Bounds().Height() > m_dataRect.Height())
{
scrollBar->SetRange(0.0, 0.0);
scrollBar->SetProportion(1.0);
}
else
{
scrollBar->SetRange(m_dataRect.top, m_dataRect.bottom - Bounds().Height());
scrollBar->SetProportion(Bounds().Height() / m_dataRect.Height());
}
}
scrollBar = ScrollBar(B_HORIZONTAL);
if (scrollBar)
{
// Disable the ScrollBar if the view is large enough to display
// the entire data-rect
if (Bounds().Width() > m_dataRect.Width())
{
scrollBar->SetRange(0.0, 0.0);
scrollBar->SetProportion(1.0);
}
else
{
scrollBar->SetRange(m_dataRect.left, m_dataRect.right - Bounds().Width());
scrollBar->SetProportion(Bounds().Width() / m_dataRect.Width());
}
}
}
// END -- DiagramView.cpp --

View File

@ -0,0 +1,257 @@
// DiagramView.h (Cortex/DiagramView)
//
// * PURPOSE
// BView and DiagramItemGroup derived class providing the
// one and only drawing context all child DiagramItems will
// use.
//
// * HISTORY
// c.lenz 25sep99 Begun
//
#ifndef __DiagramView_H__
#define __DiagramView_H__
#include "DiagramItemGroup.h"
#include <Region.h>
#include <View.h>
//class BBitmap;
#include "cortex_defs.h"
__BEGIN_CORTEX_NAMESPACE
//class DiagramBox;
class DiagramWire;
class DiagramEndPoint;
class DiagramView : public BView,
public DiagramItemGroup
{
public: // *** ctor/dtor
DiagramView(
BRect frame,
const char *name,
bool multiSelection,
uint32 resizingMode = B_FOLLOW_LEFT | B_FOLLOW_TOP,
uint32 flags = B_WILL_DRAW);
virtual ~DiagramView();
public: // *** hook functions
// is called from MessageReceived() if a wire has been dropped
// on the background or on an incompatible endpoint
virtual void connectionAborted(
DiagramEndPoint *fromWhich)
{ /* does nothing */ }
// is called from MessageReceived() if an endpoint has accepted
// a wire-drop (i.e. connection)
virtual void connectionEstablished(
DiagramEndPoint *fromWhich,
DiagramEndPoint *toWhich)
{ /* does nothing */ }
// must be implemented to return an instance of the DiagramWire
// derived class
virtual DiagramWire *createWire(
DiagramEndPoint *fromWhich,
DiagramEndPoint *woWhich) = 0;
// must be implemented to return an instance of the DiagramWire
// derived class; this version is for temporary wires used in
// drag & drop connecting
virtual DiagramWire *createWire(
DiagramEndPoint *fromWhich) = 0;
// hook called from MouseDown() if the background was hit
virtual void mouseDown(
BPoint point,
uint32 buttons,
uint32 clicks)
{ /* does nothing */ }
// hook called from MouseMoved() if the mouse is floating over
// the background (i.e. with no message attached)
virtual void mouseOver(
BPoint point,
uint32 transit)
{ /* does nothing */ }
// hook called from MouseMoved() if a message is being dragged
// over the background
virtual void messageDragged(
BPoint point,
uint32 transit,
const BMessage *message);
// hook called from MessageReceived() if a message has been
// dropped over the background
virtual void messageDropped(
BPoint point,
BMessage *message);
public: // derived from BView
// initial scrollbar update [e.moon 16nov99]
virtual void AttachedToWindow();
// draw the background and all items
virtual void Draw(
BRect updateRect);
// updates the scrollbars
virtual void FrameResized(
float width,
float height);
// return data rect [c.lenz 1mar2000]
virtual void GetPreferredSize(
float *width,
float *height);
// handles the messages M_SELECTION_CHANGED and M_WIRE_DROPPED
// and passes a dropped message on to the item it was dropped on
virtual void MessageReceived(
BMessage *message);
// handles the arrow keys for moving DiagramBoxes
virtual void KeyDown(
const char *bytes,
int32 numBytes);
// if an item is located at the click point, this function calls
// that items mouseDown() method; else a deselectAll() command is
// made and rect-tracking is initiated
virtual void MouseDown(
BPoint point);
// if an item is located under the given point, this function
// calls that items messageDragged() hook if a message is being
// dragged, and mouseOver() if not
virtual void MouseMoved(
BPoint point,
uint32 transit,
const BMessage *message);
// ends rect-tracking and wire-tracking
virtual void MouseUp(
BPoint point);
public: // *** derived from DiagramItemGroup
// extends the DiagramItemGroup implementation by setting
// the items owner and calling the attachedToDiagram() hook
// on it
virtual bool addItem(
DiagramItem *item);
// extends the DiagramItemGroup implementation by calling
// the detachedToDiagram() hook on the item
virtual bool removeItem(
DiagramItem *item);
public: // *** operations
// update the temporary wire to follow the mouse cursor
void trackWire(
BPoint point);
bool isWireTracking() const
{ return m_draggedWire; }
protected: // *** internal operations
// do the actual background drawing
void drawBackground(
BRect updateRect);
// returns the current background color
rgb_color backgroundColor() const
{ return m_backgroundColor; }
// set the background color; does not refresh the display
void setBackgroundColor(
rgb_color color);
// set the background bitmap; does not refresh the display
void setBackgroundBitmap(
BBitmap *bitmap);
// updates the region containing the rects of all boxes in
// the view (and thereby the "data-rect") and then adapts
// the scrollbars if necessary
void updateDataRect();
private: // *** internal operations
// setup a temporary wire for "live" dragging and attaches
// a message to the mouse
void _beginWireTracking(
DiagramEndPoint *fromEndPoint);
// delete the temporary dragged wire and invalidate display
void _endWireTracking();
// setups rect-tracking to additionally drag a message for
// easier identification in MouseMoved()
void _beginRectTracking(
BPoint origin);
// takes care of actually selecting/deselecting boxes when
// they intersect with the tracked rect
void _trackRect(
BPoint origin,
BPoint current);
// updates the scrollbars (if there are any) to represent
// the current data-rect
void _updateScrollBars();
private: // *** data
// the button pressed at the last mouse event
int32 m_lastButton;
// the number of clicks with the last button
int32 m_clickCount;
// the point last clicked in this view
BPoint m_lastClickPoint;
// the button currently pressed (reset to 0 on mouse-up)
// [e.moon 16nov99]
int32 m_pressedButton;
// last mouse position in screen coordinates [e.moon 16nov99]
// only valid while m_pressedButton != 0
BPoint m_lastDragPoint;
// a pointer to the temporary wire used for wire
// tracking
DiagramWire *m_draggedWire;
// contains the rects of all DiagramBoxes in this view
BRegion m_boxRegion;
// contains the rect of the view actually containing something
// (i.e. DiagramBoxes) and all free space left/above of that
BRect m_dataRect;
// true if a bitmap is used for the background; false
// if a color is used
bool m_useBackgroundBitmap;
// the background color of the view
rgb_color m_backgroundColor;
// the background bitmap of the view
BBitmap *m_backgroundBitmap;
};
__END_CORTEX_NAMESPACE
#endif // __DiagramView_H__

View File

@ -0,0 +1,186 @@
// DiagramWire.cpp
#include "DiagramWire.h"
#include "DiagramDefs.h"
#include "DiagramEndPoint.h"
#include "DiagramView.h"
#include <Message.h>
#include <Messenger.h>
__USE_CORTEX_NAMESPACE
#include <Debug.h>
#define D_METHOD(x) //PRINT (x)
#define D_MESSAGE(x) //PRINT (x)
// -------------------------------------------------------- //
// *** ctor/dtor
// -------------------------------------------------------- //
DiagramWire::DiagramWire(
DiagramEndPoint *fromWhich,
DiagramEndPoint *toWhich)
: DiagramItem(DiagramItem::M_WIRE),
m_fromEndPoint(fromWhich),
m_toEndPoint(toWhich),
m_temporary(false)
{
D_METHOD(("DiagramWire::DiagramWire()\n"));
makeDraggable(false);
ASSERT(m_fromEndPoint);
m_fromEndPoint->connect(this);
ASSERT(m_toEndPoint);
m_toEndPoint->connect(this);
}
DiagramWire::DiagramWire(
DiagramEndPoint *fromWhich,
bool isStartPoint)
: DiagramItem(DiagramItem::M_WIRE),
m_fromEndPoint(isStartPoint ? fromWhich : 0),
m_toEndPoint(isStartPoint ? 0 : fromWhich),
m_temporary(true),
m_dragEndPoint(fromWhich->connectionPoint())
{
D_METHOD(("DiagramWire::DiagramWire(temp)\n"));
makeDraggable(false);
ASSERT(fromWhich);
if (m_fromEndPoint)
{
m_fromEndPoint->connect(this);
}
else if (m_toEndPoint)
{
m_toEndPoint->connect(this);
}
}
DiagramWire::~DiagramWire()
{
D_METHOD(("DiagramWire::~DiagramWire()\n"));
if (m_fromEndPoint)
{
m_fromEndPoint->disconnect();
}
if (m_toEndPoint)
{
m_toEndPoint->disconnect();
}
}
// -------------------------------------------------------- //
// *** accessors
// -------------------------------------------------------- //
BPoint DiagramWire::startConnectionPoint() const
{
D_METHOD(("DiagramWire::startConnectionPoint()\n"));
if (m_fromEndPoint)
{
return m_fromEndPoint->connectionPoint();
}
else if (m_temporary)
{
return m_dragEndPoint;
}
return BPoint(-1.0, -1.0);
}
BPoint DiagramWire::endConnectionPoint() const
{
D_METHOD(("DiagramWire::endConnectionPoint()\n"));
if (m_toEndPoint)
{
return m_toEndPoint->connectionPoint();
}
else if (m_temporary)
{
return m_dragEndPoint;
}
return BPoint(-1.0, -1.0);
}
// -------------------------------------------------------- //
// *** derived from DiagramItem
// -------------------------------------------------------- //
float DiagramWire::howCloseTo(
BPoint point) const
{
D_METHOD(("DiagramWire::howCloseTo()\n"));
BPoint a = startConnectionPoint();
BPoint b = endConnectionPoint();
float length, result;
length = sqrt(pow(b.x - a.x, 2) + pow(b.y - a.y, 2));
result = ((a.y - point.y) * (b.x - a.x)) - ((a.x - point.x) * (b.y - a.y));
result = 3.0 - fabs(result / length);
return result;
}
void DiagramWire::draw(
BRect updateRect)
{
D_METHOD(("DiagramWire::draw()\n"));
if (view())
{
view()->PushState();
{
BRegion region, clipping;
region.Include(frame() & updateRect);
if (view()->getClippingAbove(this, &clipping))
region.Exclude(&clipping);
view()->ConstrainClippingRegion(&region);
drawWire();
}
view()->PopState();
}
}
void DiagramWire::mouseDown(
BPoint point,
uint32 buttons,
uint32 clicks)
{
D_METHOD(("DiagramWire::mouseDown()\n"));
if (clicks == 1)
{
if (isSelectable())
{
BMessage selectMsg(M_SELECTION_CHANGED);
if (modifiers() & B_SHIFT_KEY)
{
selectMsg.AddBool("replace", false);
}
else
{
selectMsg.AddBool("replace", true);
}
selectMsg.AddPointer("item", reinterpret_cast<void *>(this));
DiagramView* v = view();
BMessenger(v).SendMessage(&selectMsg);
}
}
}
void DiagramWire::messageDragged(
BPoint point,
uint32 transit,
const BMessage *message)
{
D_METHOD(("DiagramWire::messageDragged()\n"));
switch (message->what)
{
case M_WIRE_DRAGGED:
{
view()->trackWire(point);
break;
}
default:
{
DiagramItem::messageDragged(point, transit, message);
}
}
}
// END -- DiagramWire.cpp --

View File

@ -0,0 +1,140 @@
// DiagramWire.h (Cortex/DiagramView)
//
// * PURPOSE
// DiagramItem subclass serving as a graphical connection
// between two DiagramEndPoints
//
// * HISTORY
// c.lenz 25sep99 Begun
//
#ifndef __DiagramWire_H__
#define __DiagramWire_H__
#include "DiagramItem.h"
#include <Region.h>
#include <Window.h>
#include "cortex_defs.h"
__BEGIN_CORTEX_NAMESPACE
class DiagramView;
class DiagramEndPoint;
class DiagramWire : public DiagramItem
{
friend DiagramView;
public: // *** ctor/dtor
// both endpoints are set connected by this constructor
// so be careful to only pass in valid pointers
DiagramWire(
DiagramEndPoint *fromWhich,
DiagramEndPoint *toWhich);
// special constructor used only in drag&drop sessions for
// temporary visual indication of the connection process
// the isStartPoint lets you specify if the given EndPoint
// is supposed to be treated as start or end point
DiagramWire(
DiagramEndPoint *fromWhich,
bool isStartPoint = true);
virtual ~DiagramWire();
public: // *** accessors
bool isDragging() const
{ return m_temporary; }
// returns a pointer to the "start/source" endpoint
DiagramEndPoint *startPoint() const
{ return m_fromEndPoint; }
// returns the point from the m_fromEndPoints connectionPoint() method
BPoint startConnectionPoint() const;
// returns a pointer the "end/target" endpoint
DiagramEndPoint *endPoint() const
{ return m_toEndPoint; }
// returns the point from the m_toEndPoints connectionPoint() method
BPoint endConnectionPoint() const;
public: // *** hook functions
// is called from draw() to do the actual drawing
virtual void drawWire() = 0;
// is called by the connected diagramEndPoints whenever one is moved
// if the argument is NULL then both endpoints should be evaluated
virtual void endPointMoved(
DiagramEndPoint *which = 0)
{ /* does nothing */ }
public: // *** derived from DiagramItem
// returns the area in which the wire displays
virtual BRect frame() const
{ return BRect(startConnectionPoint(), endConnectionPoint()); }
// returns how close a given point is to the wire; the current
// implementation returns a wide array of values, those above
// approx. 0.5 are quite close to the wire
float howCloseTo(
BPoint point) const;
// prepares the drawing stack and clipping region, then
// calls drawWire
void draw(
BRect updateRect);
// is called from the parent DiagramViews MouseDown() implementation
// if the Wire was hit; this version initiates selection and dragging
virtual void mouseDown(
BPoint point,
uint32 buttons,
uint32 clicks);
// is called from the DiagramViews MouseMoved() when no message is being
// dragged, but the mouse has moved above the wire
virtual void mouseOver(
BPoint point,
uint32 transit)
{ /* does nothing */ }
// is called from the DiagramViews MouseMoved() when a message is being
// dragged over the DiagramWire
virtual void messageDragged(
BPoint point,
uint32 transit,
const BMessage *message);
// is called from the DiagramViews MessageReceived() function when a
// message has been dropped on the DiagramWire
virtual void messageDropped(
BPoint point,
BMessage *message)
{ /* does nothing */ }
private: // *** data
// pointer to the "from" EndPoint as assigned in the ctor
DiagramEndPoint *m_fromEndPoint;
// pointer to the "to" EndPoint as assigned in the ctor
DiagramEndPoint *m_toEndPoint;
// indicates that this is a connection used in a drag&drop session
// and will be deleted after that
bool m_temporary;
// contains a BPoint for "temporary connections"
BPoint m_dragEndPoint;
};
__END_CORTEX_NAMESPACE
#endif // __DiagramWire_H__

View File

@ -0,0 +1,293 @@
// DormantNodeListItem.cpp
#include "DormantNodeListItem.h"
// InfoWindow
#include "InfoWindowManager.h"
// Support
#include "MediaIcon.h"
// TipManager
#include "TipManager.h"
// Application Kit
#include <Application.h>
// Interface Kit
#include <PopUpMenu.h>
#include <MenuItem.h>
// Media Kit
#include <MediaRoster.h>
#include <MediaAddOn.h>
__USE_CORTEX_NAMESPACE
#include <Debug.h>
#define D_ALLOC(x) //PRINT (x) // ctor/dtor
#define D_HOOK(x) //PRINT (x) // BListItem impl.
#define D_OPERATION(x) //PRINT (x) // operations
#define D_COMPARE(x) //PRINT (x) // compare functions
// -------------------------------------------------------- //
// constants
// -------------------------------------------------------- //
const float DormantNodeListItem::M_ICON_H_MARGIN = 3.0;
const float DormantNodeListItem::M_ICON_V_MARGIN = 1.0;
// -------------------------------------------------------- //
// ctor/dtor
// -------------------------------------------------------- //
DormantNodeListItem::DormantNodeListItem(
const dormant_node_info &nodeInfo)
: m_info(nodeInfo),
m_icon(0) {
D_ALLOC(("DormantNodeListItem::DormantNodeListItem()\n"));
m_icon = new MediaIcon(nodeInfo, B_MINI_ICON);
}
DormantNodeListItem::~DormantNodeListItem() {
D_ALLOC(("DormantNodeListItem::~DormantNodeListItem()\n"));
delete m_icon;
}
// -------------------------------------------------------- //
// BListItem impl.
// -------------------------------------------------------- //
void DormantNodeListItem::DrawItem(
BView *owner,
BRect frame,
bool drawEverything) {
D_HOOK(("DormantNodeListItem::DrawItem()\n"));
// Draw icon
if (m_icon) {
BRect r = frame;
r.left += M_ICON_H_MARGIN;
r.top += (frame.Height() / 2.0) - (B_MINI_ICON / 2.0);
r.right = r.left + B_MINI_ICON - 1.0;
r.bottom = r.top + B_MINI_ICON - 1.0;
if (IsSelected()) {
owner->SetHighColor(255.0, 255.0, 255.0, 255.0);
owner->FillRect(r);
owner->SetDrawingMode(B_OP_INVERT);
owner->DrawBitmap(m_icon, r.LeftTop());
owner->SetDrawingMode(B_OP_ALPHA);
owner->SetHighColor(0.0, 0.0, 0.0, 180.0);
owner->SetBlendingMode(B_CONSTANT_ALPHA, B_ALPHA_COMPOSITE);
owner->DrawBitmap(m_icon, r.LeftTop());
owner->SetDrawingMode(B_OP_OVER);
}
else {
owner->SetDrawingMode(B_OP_OVER);
owner->DrawBitmap(m_icon, r.LeftTop());
}
}
// Draw label
BRect r = frame;
r.left += 2 * M_ICON_H_MARGIN + B_MINI_ICON;
r.top += (frame.Height() / 2.0) - (m_fontHeight.ascent / 2.0);
r.right = r.left + Width();
r.bottom = r.top + m_fontHeight.ascent + m_fontHeight.descent;
if (IsSelected() || drawEverything) {
if (IsSelected()) {
owner->SetHighColor(16.0, 64.0, 96.0, 255.0);
}
else {
owner->SetHighColor(owner->ViewColor());
}
owner->FillRect(r);
}
if (IsSelected()) {
owner->SetHighColor(255.0, 255.0, 255.0, 255.0);
}
else {
owner->SetHighColor(0.0, 0.0, 0.0, 0.0);
}
BPoint labelOffset(r.left + 1.0, r.bottom - m_fontHeight.descent);
owner->DrawString(m_info.name, labelOffset);
// cache the frame rect
m_frame = frame;
}
void DormantNodeListItem::Update(
BView *owner,
const BFont *font) {
D_HOOK(("DormantNodeListItem::Update()\n"));
BListItem::Update(owner, font);
SetWidth(font->StringWidth(m_info.name));
owner->GetFontHeight(&m_fontHeight);
float newHeight = m_fontHeight.ascent + m_fontHeight.descent + m_fontHeight.leading;
if (newHeight < B_MINI_ICON) {
newHeight = B_MINI_ICON;
}
newHeight += 2 * M_ICON_V_MARGIN;
if (Height() < newHeight) {
SetHeight(newHeight);
}
}
// -------------------------------------------------------- //
// BListItem impl.
// -------------------------------------------------------- //
void DormantNodeListItem::mouseOver(
BView *owner,
BPoint point,
uint32 transit) {
D_OPERATION(("DormantNodeListItem::mouseOver()\n"));
switch (transit) {
case B_ENTERED_VIEW: {
TipManager *tips = TipManager::Instance();
dormant_flavor_info flavorInfo;
BMediaRoster *roster = BMediaRoster::CurrentRoster();
if (roster && roster->GetDormantFlavorInfoFor(info(), &flavorInfo) == B_OK) {
BString tip = flavorInfo.info;
if (tip == "") {
tip = m_info.name;
}
tips->showTip(tip.String(), owner->ConvertToScreen(m_frame));
}
break;
}
case B_EXITED_VIEW: {
TipManager *tips = TipManager::Instance();
tips->hideTip(owner->ConvertToScreen(m_frame));
break;
}
}
}
BRect DormantNodeListItem::getRealFrame(
const BFont *font) const {
D_OPERATION(("DormantNodeListItem::getRealFrame()\n"));
BRect r(0.0, 0.0, -1.0, -1.0);
if (m_frame.IsValid()) {
r = m_frame;
r.right = r.left + B_MINI_ICON + 2 * M_ICON_H_MARGIN;
r.right += font->StringWidth(m_info.name);
}
else {
r.right = font->StringWidth(m_info.name);
r.right += B_MINI_ICON + 2 * M_ICON_H_MARGIN + 5.0;
font_height fh;
font->GetHeight(&fh);
r.bottom = fh.ascent + fh.descent + fh.leading;
if (r.bottom < B_MINI_ICON) {
r.bottom = B_MINI_ICON;
}
r.bottom += 2 * M_ICON_V_MARGIN;
if (Height() > r.bottom) {
r.bottom = Height();
}
}
return r;
}
BBitmap *DormantNodeListItem::getDragBitmap() {
D_OPERATION(("DormantNodeListItem::getDragBitmap()\n"));
// Prepare Bitmap for Drag & Drop
BBitmap *dragBitmap = new BBitmap(m_frame.OffsetToCopy(BPoint(0.0, 0.0)), B_RGBA32, true);
dragBitmap->Lock(); {
BView *dragView = new BView(dragBitmap->Bounds(), "", B_FOLLOW_NONE, 0);
dragBitmap->AddChild(dragView);
dragView->SetOrigin(0.0, 0.0);
dragView->SetHighColor(0.0, 0.0, 0.0, 0.0);
dragView->FillRect(dragView->Bounds());
dragView->SetDrawingMode(B_OP_ALPHA);
dragView->SetHighColor(0.0, 0.0, 0.0, 128.0);
dragView->SetBlendingMode(B_CONSTANT_ALPHA, B_ALPHA_COMPOSITE);
// Drawing code back again
if (m_icon) {
BRect r = dragView->Bounds();
r.left += M_ICON_H_MARGIN;
r.top += (m_frame.Height() / 2.0) - (B_MINI_ICON / 2.0);
r.right = r.left + B_MINI_ICON - 1.0;
r.bottom = r.top + B_MINI_ICON - 1.0;
dragView->DrawBitmap(m_icon, r.LeftTop());
}
BRect r = dragView->Bounds();
r.left += 2 * M_ICON_H_MARGIN + B_MINI_ICON;
r.top += (m_frame.Height() / 2.0) - (m_fontHeight.ascent / 2.0);
r.right = r.left + Width();
r.bottom = r.top + m_fontHeight.ascent + m_fontHeight.descent;
BPoint labelOffset(r.left + 1.0, r.bottom - m_fontHeight.descent);
dragView->DrawString(m_info.name, labelOffset);
dragView->Sync();
}
dragBitmap->Unlock();
return dragBitmap;
}
void DormantNodeListItem::showContextMenu(
BPoint point,
BView *owner) {
D_OPERATION(("DormantNodeListItem::showContextMenu()\n"));
BPopUpMenu *menu = new BPopUpMenu("DormantNodeListItem PopUp", false, false, B_ITEMS_IN_COLUMN);
menu->SetFont(be_plain_font);
// Add the "Get Info" item
BMessage *message = new BMessage(InfoWindowManager::M_INFO_WINDOW_REQUESTED);
menu->AddItem(new BMenuItem("Get Info", message));
menu->SetTargetForItems(owner);
owner->ConvertToScreen(&point);
point -= BPoint(1.0, 1.0);
menu->Go(point, true, true, true);
}
// -------------------------------------------------------- //
// *** compare functions (friend)
// -------------------------------------------------------- //
int __CORTEX_NAMESPACE__ compareName(
const void *lValue,
const void *rValue) {
D_COMPARE(("compareSelectionTime()\n"));
int returnValue = 0;
const DormantNodeListItem *lItem = *(reinterpret_cast<const DormantNodeListItem* const*>
(reinterpret_cast<const void* const*>(lValue)));
const DormantNodeListItem *rItem = *(reinterpret_cast<const DormantNodeListItem* const*>
(reinterpret_cast<const void* const*>(rValue)));
BString lString = lItem->info().name;
lString.ToUpper();
BString rString = rItem->info().name;
rString.ToUpper();
if (lString < rString) {
returnValue = -1;
}
else if (lString > rString) {
returnValue = 1;
}
return returnValue;
}
int __CORTEX_NAMESPACE__ compareAddOnID(
const void *lValue,
const void *rValue) {
D_COMPARE(("compareAddOnID()\n"));
int returnValue = 0;
const DormantNodeListItem *lItem = *(reinterpret_cast<const DormantNodeListItem* const*>
(reinterpret_cast<const void* const*>(lValue)));
const DormantNodeListItem *rItem = *(reinterpret_cast<const DormantNodeListItem* const*>
(reinterpret_cast<const void* const*>(rValue)));
if (lItem->info().addon < rItem->info().addon) {
returnValue = -1;
}
else if (lItem->info().addon > rItem->info().addon) {
returnValue = 1;
}
return returnValue;
}
// END -- DormantNodeListItem.cpp --

View File

@ -0,0 +1,100 @@
// DormantNodeListItem.h
// e.moon 2jun99
//
// * PURPOSE
// - represent a single dormant (add-on) media node in a
// list view.
//
// * HISTORY
// 22oct99 c.lenz complete rewrite
// 27oct99 c.lenz added tooltip support
#ifndef __DormantNodeListItem_H__
#define __DormantNodeListItem_H__
// Interface Kit
#include <Bitmap.h>
#include <Font.h>
#include <ListItem.h>
// Media Kit
#include <MediaAddOn.h>
#include "cortex_defs.h"
__BEGIN_CORTEX_NAMESPACE
class DormantNodeView;
class MediaIcon;
class DormantNodeListItem :
public BListItem {
typedef BListItem _inherited;
public: // *** constants
// [e.moon 26oct99] moved definition to DormantNodeListItem.cpp
// to appease the Metrowerks compiler.
static const float M_ICON_H_MARGIN;
static const float M_ICON_V_MARGIN;
public: // *** ctor/dtor
DormantNodeListItem(
const dormant_node_info &nodeInfo);
virtual ~DormantNodeListItem();
public: // *** accessors
const dormant_node_info &info() const
{ return m_info; }
public: // *** operations
void mouseOver(
BView *owner,
BPoint point,
uint32 transit);
BRect getRealFrame(
const BFont *font) const;
BBitmap *getDragBitmap();
void showContextMenu(
BPoint point,
BView *owner);
public: // *** BListItem impl.
virtual void DrawItem(
BView *owner,
BRect frame,
bool drawEverything = false);
virtual void Update(
BView *owner,
const BFont *fFont);
protected: // *** compare functions
friend int compareName(
const void *lValue,
const void *rValue);
friend int compareAddOnID(
const void *lValue,
const void *rValue);
private: // *** data
dormant_node_info m_info;
BRect m_frame;
font_height m_fontHeight;
MediaIcon *m_icon;
};
__END_CORTEX_NAMESPACE
#endif /*__DormantNodeListItem_H__*/

View File

@ -0,0 +1,321 @@
// DormantNodeView.cpp
#include "DormantNodeView.h"
// DormantNodeView
#include "DormantNodeWindow.h"
#include "DormantNodeListItem.h"
// InfoWindow
#include "InfoWindowManager.h"
// Interface Kit
#include <Deskbar.h>
#include <Region.h>
#include <Screen.h>
#include <ScrollBar.h>
// Media Kit
#include <MediaRoster.h>
// Storage Kit
#include <Mime.h>
__USE_CORTEX_NAMESPACE
#include <Debug.h>
#define D_ALLOC(x) //PRINT (x) // ctor/dtor
#define D_HOOK(x) //PRINT (x) // BListView impl.
#define D_MESSAGE(x) //PRINT (x) // MessageReceived()
#define D_INTERNAL(x) //PRINT (x) // internal operations
// -------------------------------------------------------- //
// ctor/dtor (public)
// -------------------------------------------------------- //
DormantNodeView::DormantNodeView(
BRect frame,
const char *name,
uint32 resizeMode)
: BListView(frame, name, B_SINGLE_SELECTION_LIST, resizeMode),
m_lastItemUnder(0) {
D_ALLOC(("DormantNodeView::DormantNodeView()\n"));
}
DormantNodeView::~DormantNodeView() {
D_ALLOC(("DormantNodeView::~DormantNodeView()\n"));
}
// -------------------------------------------------------- //
// BListView impl. (public)
// -------------------------------------------------------- //
void DormantNodeView::AttachedToWindow() {
D_HOOK(("DormantNodeView::AttachedToWindow()\n"));
// populate the list
_populateList();
// Start watching the MediaRoster for flavor changes
BMediaRoster *roster = BMediaRoster::CurrentRoster();
if (roster) {
BMessenger messenger(this, Window());
roster->StartWatching(messenger, B_MEDIA_FLAVORS_CHANGED);
}
}
void DormantNodeView::DetachedFromWindow() {
D_HOOK(("DormantNodeView::DetachedFromWindow()\n"));
// delete the lists contents
_freeList();
// Stop watching the MediaRoster for flavor changes
BMediaRoster *roster = BMediaRoster::CurrentRoster();
if (roster) {
BMessenger messenger(this, Window());
roster->StopWatching(messenger, B_MEDIA_FLAVORS_CHANGED);
}
}
void DormantNodeView::GetPreferredSize(
float* width,
float* height) {
D_HOOK(("DormantNodeView::GetPreferredSize()\n"));
// calculate the accumulated size of all list items
*width = 0;
*height = 0;
for (int32 i = 0; i < CountItems(); i++) {
DormantNodeListItem *item;
item = dynamic_cast<DormantNodeListItem *>(ItemAt(i));
if (item) {
BRect r = item->getRealFrame(be_plain_font);
if (r.Width() > *width) {
*width = r.Width();
}
*height += r.Height() + 1.0;
}
}
}
void DormantNodeView::MessageReceived(
BMessage *message) {
D_MESSAGE(("DormantNodeView::MessageReceived()\n"));
switch (message->what) {
case B_MEDIA_FLAVORS_CHANGED: {
D_MESSAGE((" -> B_MEDIA_FLAVORS_CHANGED\n"));
// init & re-populate the list
int32 addOnID = 0;
if (message->FindInt32("be:addon_id", &addOnID) != B_OK) {
D_MESSAGE((" -> messages doesn't contain 'be:addon_id'!\n"));
return;
}
_updateList(addOnID);
break;
}
case InfoWindowManager::M_INFO_WINDOW_REQUESTED: {
D_MESSAGE((" -> InfoWindowManager::M_INFO_WINDOW_REQUESTED)\n"));
DormantNodeListItem *item;
item = dynamic_cast<DormantNodeListItem *>(ItemAt(CurrentSelection()));
if (item) {
InfoWindowManager *manager = InfoWindowManager::Instance();
if (manager && manager->Lock()) {
manager->openWindowFor(item->info());
manager->Unlock();
}
}
break;
}
default: {
_inherited::MessageReceived(message);
}
}
}
void DormantNodeView::MouseDown(
BPoint point) {
D_HOOK(("DormantNodeView::MouseDown()\n"));
BMessage* message = Window()->CurrentMessage();
int32 buttons = message->FindInt32("buttons");
if (buttons == B_SECONDARY_MOUSE_BUTTON) {
int32 index;
if ((index = IndexOf(point)) >= 0) {
DormantNodeListItem *item = dynamic_cast<DormantNodeListItem *>(ItemAt(index));
if (item) {
Select(index);
BRect r = item->getRealFrame(be_plain_font);
if (r.Contains(point)) {
item->showContextMenu(point, this);
}
}
}
}
_inherited::MouseDown(point);
}
void DormantNodeView::MouseMoved(
BPoint point,
uint32 transit,
const BMessage *message) {
D_HOOK(("DormantNodeView::MouseMoved()\n"));
int32 index;
if (!message && ((index = IndexOf(point)) >= 0)) {
DormantNodeListItem *item = dynamic_cast<DormantNodeListItem *>(ItemAt(index));
DormantNodeListItem *last = dynamic_cast<DormantNodeListItem *>(m_lastItemUnder);
BRect r = item->getRealFrame(be_plain_font);
if (item && r.Contains(point)) {
if (item != last) {
if (last)
last->mouseOver(this, point, B_EXITED_VIEW);
item->mouseOver(this, point, B_ENTERED_VIEW);
m_lastItemUnder = item;
}
else {
item->mouseOver(this, point, B_INSIDE_VIEW);
}
}
else if (last) {
last->mouseOver(this, point, B_EXITED_VIEW);
}
}
_inherited::MouseMoved(point, transit, message);
}
bool DormantNodeView::InitiateDrag(
BPoint point,
int32 index,
bool wasSelected) {
D_HOOK(("DormantNodeView::InitiateDrag()\n"));
DormantNodeListItem *item = dynamic_cast<DormantNodeListItem *>(ItemAt(CurrentSelection()));
if (item) {
BMessage dragMsg(M_INSTANTIATE_NODE);
dragMsg.AddData("which", B_RAW_TYPE,
reinterpret_cast<const void *>(&item->info()),
sizeof(item->info()));
point -= ItemFrame(index).LeftTop();
DragMessage(&dragMsg, item->getDragBitmap(), B_OP_ALPHA, point);
return true;
}
return false;
}
// -------------------------------------------------------- //
// internal operations (private)
// -------------------------------------------------------- //
void DormantNodeView::_populateList() {
D_INTERNAL(("DormantNodeView::_populateList()\n"));
// init the resizable node-info buffer
BMediaRoster *roster = BMediaRoster::CurrentRoster();
const int32 bufferInc = 64;
int32 bufferSize = bufferInc;
dormant_node_info *infoBuffer = new dormant_node_info[bufferSize];
int32 numNodes;
// fill the buffer
while (true) {
numNodes = bufferSize;
status_t error = roster->GetDormantNodes(infoBuffer, &numNodes);
if (error) {
return;
}
if (numNodes < bufferSize) {
break;
}
// reallocate buffer & try again
delete [] infoBuffer;
bufferSize += bufferInc;
infoBuffer = new dormant_node_info[bufferSize];
}
// populate the list
for (int32 i = 0; i < numNodes; i++) {
DormantNodeListItem *item = new DormantNodeListItem(infoBuffer[i]);
AddItem(item);
}
SortItems(compareName);
}
void DormantNodeView::_freeList() {
D_HOOK(("DormantNodeView::_freeList()\n"));
// remove and delete all items in the list
while (CountItems() > 0) {
BListItem *item = ItemAt(0);
if (RemoveItem(item)) {
delete item;
}
}
}
void DormantNodeView::_updateList(
int32 addOnID) {
D_INTERNAL(("DormantNodeView::_updateList(%ld)\n", addOnID));
// init the resizable node-info buffer
BMediaRoster *roster = BMediaRoster::CurrentRoster();
const int32 bufferInc = 64;
int32 bufferSize = bufferInc;
dormant_node_info *infoBuffer = new dormant_node_info[bufferSize];
int32 numNodes;
// fill the buffer
while (true) {
numNodes = bufferSize;
status_t error = roster->GetDormantNodes(infoBuffer, &numNodes);
if (error) {
return;
}
if (numNodes < bufferSize) {
break;
}
// reallocate buffer & try again
delete [] infoBuffer;
bufferSize += bufferInc;
infoBuffer = new dormant_node_info[bufferSize];
}
// sort the list by add-on id to avoid multiple searches through
// the list
SortItems(compareAddOnID);
// Remove all nodes managed by this add-on
int32 start;
for (start = 0; start < CountItems(); start++) {
DormantNodeListItem *item = dynamic_cast<DormantNodeListItem *>(ItemAt(start));
if (item && (item->info().addon == addOnID)) {
break;
}
}
int32 count = 0;
for (int32 i = start; start < CountItems(); i++) {
DormantNodeListItem *item = dynamic_cast<DormantNodeListItem *>(ItemAt(i));
if (!item || (item->info().addon != addOnID)) {
break;
}
count++;
}
RemoveItems(start, count);
// add the items
for (int32 i = 0; i < numNodes; i++) {
if (infoBuffer[i].addon != addOnID) {
continue;
}
AddItem(new DormantNodeListItem(infoBuffer[i]));
}
SortItems(compareName);
}
// END -- DormantNodeView.cpp --

View File

@ -0,0 +1,83 @@
// DormantNodeView.h
// c.lenz 22oct99
//
// RESPONSIBILITIES
// - simple extension of BListView to support
// drag & drop
//
// HISTORY
// c.lenz 22oct99 Begun
// c.lenz 27oct99 Added ToolTip support
#ifndef __DormantNodeView_H__
#define __DormantNodeView_H__
// Interface Kit
#include <ListView.h>
#include "cortex_defs.h"
__BEGIN_CORTEX_NAMESPACE
class DormantNodeView :
public BListView {
typedef BListView _inherited;
public: // *** messages
enum message_t {
// OUTBOUND:
// B_RAW_TYPE "which" dormant_node_info
M_INSTANTIATE_NODE = 'dNV0'
};
public: // *** ctor/dtor
DormantNodeView(
BRect frame,
const char *name,
uint32 resizeMode);
virtual ~DormantNodeView();
public: // *** BListView impl.
virtual void AttachedToWindow();
virtual void DetachedFromWindow();
virtual void GetPreferredSize(
float* width,
float* height);
virtual void MessageReceived(
BMessage *message);
virtual void MouseDown(
BPoint point);
virtual void MouseMoved(
BPoint point,
uint32 transit,
const BMessage *message);
virtual bool InitiateDrag(
BPoint point,
int32 index,
bool wasSelected);
private: // *** internal operations
void _populateList();
void _freeList();
void _updateList(
int32 addOnID);
private: // *** data
BListItem *m_lastItemUnder;
};
__END_CORTEX_NAMESPACE
#endif /*__DormantNodeView_H__*/

View File

@ -0,0 +1,154 @@
// DormantNodeWindow.cpp
// e.moon 2jun99
#include "DormantNodeWindow.h"
// DormantNodeView
#include "DormantNodeView.h"
#include "RouteWindow.h"
// Application Kit
#include <Application.h>
// Interface Kit
#include <Screen.h>
#include <ScrollBar.h>
__USE_CORTEX_NAMESPACE
#include <Debug.h>
#define D_ALLOC(x) //PRINT (x) // ctor/dtor
#define D_HOOK(x) //PRINT (x) // BWindow impl.
#define D_MESSAGE(x) //PRINT (x) // MessageReceived()
#define D_INTERNAL(x) //PRINT (x) // internal operations
// -------------------------------------------------------- //
// constants
// -------------------------------------------------------- //
// this should be a bit more sophisticated :)
const BRect DormantNodeWindow::s_initFrame(500.0, 350.0, 640.0, 480.0);
// -------------------------------------------------------- //
// ctor/dtor
// -------------------------------------------------------- //
DormantNodeWindow::DormantNodeWindow(
BWindow* parent)
: BWindow(s_initFrame, "Media Add-Ons",
B_FLOATING_WINDOW_LOOK,
B_FLOATING_SUBSET_WINDOW_FEEL,
B_WILL_ACCEPT_FIRST_CLICK|B_AVOID_FOCUS|B_ASYNCHRONOUS_CONTROLS),
m_parent(parent),
m_zoomed(false),
m_zooming(false) {
D_ALLOC(("DormantNodeWindow::DormantNodeWindow()\n"));
ASSERT(m_parent);
AddToSubset(m_parent);
// Create the ListView
BRect r = Bounds();
r.right -= B_V_SCROLL_BAR_WIDTH;
m_listView = new DormantNodeView(r, "Dormant Node ListView", B_FOLLOW_ALL_SIDES);
// Add the vertical ScrollBar
r.left = r.right + 1.0;
r.right = r.left + B_V_SCROLL_BAR_WIDTH;
r.InsetBy(0.0, -1.0);
BScrollBar *scrollBar;
AddChild(scrollBar = new BScrollBar(r, "", m_listView, 0.0, 0.0, B_VERTICAL));
// Add the ListView
AddChild(m_listView);
_constrainToScreen();
}
DormantNodeWindow::~DormantNodeWindow() {
D_ALLOC(("DormantNodeWindow::~DormantNodeWindow()\n"));
}
// -------------------------------------------------------- //
// BWindow impl.
// -------------------------------------------------------- //
bool DormantNodeWindow::QuitRequested() {
D_HOOK(("DormantNodeWindow::QuitRequested()\n"));
// [e.moon 29nov99] the RouteWindow is now responsible for
// closing me
m_parent->PostMessage(RouteWindow::M_TOGGLE_DORMANT_NODE_WINDOW);
return false;
}
void DormantNodeWindow::Zoom(
BPoint origin,
float width,
float height) {
D_HOOK(("DormantNodeWindow::Zoom()\n"));
m_zooming = true;
BScreen screen(this);
if (!screen.Frame().Contains(Frame())) {
m_zoomed = false;
}
if (!m_zoomed) {
// resize to the ideal size
m_manualSize = Bounds();
m_listView->GetPreferredSize(&width, &height);
ResizeTo(width + B_V_SCROLL_BAR_WIDTH, height);
m_zoomed = true;
_constrainToScreen();
}
else {
// resize to the most recent manual size
ResizeTo(m_manualSize.Width(), m_manualSize.Height());
m_zoomed = false;
}
}
// -------------------------------------------------------- //
// internal operations
// -------------------------------------------------------- //
void DormantNodeWindow::_constrainToScreen() {
D_INTERNAL(("DormantNodeWindow::_constrainToScreen()\n"));
BScreen screen(this);
BRect screenRect = screen.Frame();
BRect windowRect = Frame();
// if the window is outside the screen rect
// move it to the default position
if (!screenRect.Intersects(windowRect)) {
windowRect.OffsetTo(screenRect.LeftTop());
MoveTo(windowRect.LeftTop());
windowRect = Frame();
}
// if the window is larger than the screen rect
// resize it to fit at each side
if (!screenRect.Contains(windowRect)) {
if (windowRect.left < screenRect.left) {
windowRect.left = screenRect.left + 5.0;
MoveTo(windowRect.LeftTop());
windowRect = Frame();
}
if (windowRect.top < screenRect.top) {
windowRect.top = screenRect.top + 5.0;
MoveTo(windowRect.LeftTop());
windowRect = Frame();
}
if (windowRect.right > screenRect.right) {
windowRect.right = screenRect.right - 5.0;
}
if (windowRect.bottom > screenRect.bottom) {
windowRect.bottom = screenRect.bottom - 5.0;
}
ResizeTo(windowRect.Width(), windowRect.Height());
}
}
// END -- DormantNodeWindow.cpp --

View File

@ -0,0 +1,57 @@
// DormantNodeWindow.h
// e.moon 2jun99
#ifndef __DormantNodeWindow_H__
#define __DormantNodeWindow_H__
// Interface Kit
#include <Window.h>
#include "cortex_defs.h"
__BEGIN_CORTEX_NAMESPACE
class DormantNodeView;
class DormantNodeWindow :
public BWindow {
typedef BWindow _inherited;
public: // *** ctor/dtor
DormantNodeWindow(
BWindow* parent);
virtual ~DormantNodeWindow();
public: // *** BWindow impl.
bool QuitRequested();
void Zoom(
BPoint origin,
float width,
float height);
private: // *** internal operations
void _constrainToScreen();
private: // *** data
BWindow* m_parent;
DormantNodeView* m_listView;
BRect m_manualSize;
bool m_zoomed;
bool m_zooming;
private: // *** internal constants
static const BRect s_initFrame;
};
__END_CORTEX_NAMESPACE
#endif /*__DormantNodeWindow_H__*/

View File

@ -0,0 +1,78 @@
// AppNodeInfoView.cpp
#include "AppNodeInfoView.h"
// NodeManager
#include "NodeRef.h"
// Support
#include "MediaIcon.h"
#include "MediaString.h"
// Application Kit
#include <Roster.h>
// Media Kit
#include <MediaNode.h>
#include <MediaRoster.h>
// Storage Kit
#include <AppFileInfo.h>
#include <Entry.h>
#include <File.h>
#include <Path.h>
__USE_CORTEX_NAMESPACE
#include <Debug.h>
#define D_METHOD(x) //PRINT (x)
// -------------------------------------------------------- //
// *** ctor/dtor (public)
// -------------------------------------------------------- //
AppNodeInfoView::AppNodeInfoView(
const NodeRef *ref)
: LiveNodeInfoView(ref)
{
D_METHOD(("AppNodeInfoView::AppNodeInfoView()\n"));
// adjust view properties
setSideBarWidth(be_plain_font->StringWidth(" File Format ") + 2 * InfoView::M_H_MARGIN);
setSubTitle("Application-Owned Node");
// add separator
addField("", "");
port_info portInfo;
app_info appInfo;
if ((get_port_info(ref->node().port, &portInfo) == B_OK)
&& (be_roster->GetRunningAppInfo(portInfo.team, &appInfo) == B_OK))
{
BEntry appEntry(&appInfo.ref);
char appName[B_FILE_NAME_LENGTH];
if ((appEntry.InitCheck() == B_OK)
&& (appEntry.GetName(appName) == B_OK))
{
addField("Application", appName);
}
BFile appFile(&appInfo.ref, B_READ_ONLY);
if (appFile.InitCheck() == B_OK)
{
BAppFileInfo appFileInfo(&appFile);
if (appFileInfo.InitCheck() == B_OK)
{
version_info appVersion;
if (appFileInfo.GetVersionInfo(&appVersion, B_APP_VERSION_KIND) == B_OK)
{
addField("Version", appVersion.long_info);
}
}
}
addField("Signature", appInfo.signature);
}
}
AppNodeInfoView::~AppNodeInfoView()
{
D_METHOD(("AppNodeInfoView::~AppNodeInfoView()\n"));
}
// END -- AppNodeInfoView.cpp --

View File

@ -0,0 +1,36 @@
// AppNodeInfoView.h (Cortex/InfoView)
//
// * PURPOSE
// In addition to the fields defined by its base class
// LiveNodeInfoView, this class defines fields about
// the application in which the node 'lives'
//
// * HISTORY
// c.lenz 3dec99 Begun
//
#ifndef __AppNodeInfoView_H__
#define __AppNodeInfoView_H__
#include "LiveNodeInfoView.h"
#include "cortex_defs.h"
__BEGIN_CORTEX_NAMESPACE
class NodeRef;
class AppNodeInfoView : public LiveNodeInfoView
{
public: // *** ctor/dtor
// add app related fields to the view by looking at
// the nodes port and querying the application roster
AppNodeInfoView(
const NodeRef *ref);
virtual ~AppNodeInfoView();
};
__END_CORTEX_NAMESPACE
#endif /* __AppNodeInfoView_H__ */

View File

@ -0,0 +1,213 @@
// ConnectionInfoView.cpp
#include "ConnectionInfoView.h"
// InfoView
#include "InfoWindowManager.h"
// Support
#include "MediaIcon.h"
#include "MediaString.h"
// NodeManager
#include "Connection.h"
// MediaKit
#include <MediaDefs.h>
__USE_CORTEX_NAMESPACE
#include <Debug.h>
#define D_METHOD(x) //PRINT (x)
#define D_MESSAGE(x) //PRINT (x)
// -------------------------------------------------------- //
// *** ctor/dtor (public)
// -------------------------------------------------------- //
ConnectionInfoView::ConnectionInfoView(
const Connection &connection)
: InfoView("Connection", "", 0),
m_source(connection.source()),
m_destination(connection.destination())
{
D_METHOD(("ConnectionInfoView::ConnectionInfoView()\n"));
setSideBarWidth(be_plain_font->StringWidth(" Destination ")
+ 2 * InfoView::M_H_MARGIN);
media_input input;
media_output output;
if (connection.getOutput(&output) == B_OK) {
// add "Source" field
BString s;
s << output.name;
if (s.Length() > 0)
s << " ";
s << "(" << MediaString::getStringFor(output.source) << ")";
addField("Source", s);
}
if (connection.getInput(&input) == B_OK) {
// add "Destination" field
BString s;
s << input.name;
if (s.Length() > 0)
s << " ";
s << "(" << MediaString::getStringFor(input.destination) << ")";
addField("Destination", s);
}
// add a separator field
addField("", "");
// add "Media Type" field
addField("Media Type", MediaString::getStringFor(connection.format().type));
// add the format fields
_addFormatFields(connection.format());
}
ConnectionInfoView::~ConnectionInfoView()
{
D_METHOD(("ConnectionInfoView::~ConnectionInfoView()\n"));
}
// -------------------------------------------------------- //
// *** internal operations (private)
// -------------------------------------------------------- //
void ConnectionInfoView::_addFormatFields(
const media_format &format) {
D_METHOD(("ConnectionInfoView::_addFormatFields()\n"));
switch (format.type) {
case B_MEDIA_RAW_AUDIO: {
// adjust view properties
setSideBarWidth(be_plain_font->StringWidth(" Sample Rate ") + 2 * InfoView::M_H_MARGIN);
BString s;
// add "Format" field
s = MediaString::forAudioFormat(format.u.raw_audio.format,
format.u.raw_audio.valid_bits);
addField("Format", s);
// add "Sample Rate" field
s = MediaString::forAudioFrameRate(format.u.raw_audio.frame_rate);
addField("Sample Rate", s);
// add "Channels" field
s = MediaString::forAudioChannelCount(format.u.raw_audio.channel_count);
addField("Channels", s);
// add "Channel Mask" field
s = MediaString::forAudioChannelMask(format.u.raw_audio.channel_mask);
addField("Channel Mask", s);
// add "Matrix Mask" field
s = MediaString::forAudioMatrixMask(format.u.raw_audio.matrix_mask);
addField("Matrix Mask", s);
// add the "Byte Order" field
s = MediaString::forAudioByteOrder(format.u.raw_audio.byte_order);
addField("Byte Order", s);
// add the "Buffer Size" field
s = MediaString::forAudioBufferSize(format.u.raw_audio.buffer_size);
addField("Buffer Size", s);
break;
}
case B_MEDIA_RAW_VIDEO: {
// adjust view properties
setSideBarWidth(be_plain_font->StringWidth(" Video Data Between ") + 2 * InfoView::M_H_MARGIN);
BString s;
// add the "Format" field
s = MediaString::forVideoFormat(format.u.raw_video.display.format);
addField("Format", s);
// add the "Resolution" field
s = MediaString::forVideoResolution(format.u.raw_video.display.line_width,
format.u.raw_video.display.line_count);
addField("Resolution", s);
// add the "Field Rate" field
s = MediaString::forVideoFieldRate(format.u.raw_video.field_rate,
format.u.raw_video.interlace);
addField("Field Rate", s);
// add the "Orientation" field
s = MediaString::forVideoOrientation(format.u.raw_video.orientation);
addField("Orientation", s);
// add the "Aspect Ratio" field
s = MediaString::forVideoAspectRatio(format.u.raw_video.pixel_width_aspect,
format.u.raw_video.pixel_height_aspect);
addField("Aspect Ratio", s);
// add the "Active Lines" field
s = MediaString::forVideoActiveLines(format.u.raw_video.first_active,
format.u.raw_video.last_active);
addField("Active Lines", s);
// add the "Offset" field
s = MediaString::forVideoOffset(format.u.raw_video.display.pixel_offset,
format.u.raw_video.display.line_offset);
addField("Offset", s);
break;
}
case B_MEDIA_ENCODED_AUDIO: {
// adjust view properties
setSideBarWidth(be_plain_font->StringWidth(" Frame Size ") + 2 * InfoView::M_H_MARGIN);
BString s;
// add the "Bit Rate" field
s = MediaString::forAudioBitRate(format.u.encoded_audio.bit_rate);
addField("Bit Rate", s);
// add the "Frame Size" field
s = MediaString::forAudioFrameSize(format.u.encoded_audio.frame_size);
addField("Frame Size", s);
break;
}
case B_MEDIA_ENCODED_VIDEO: {
// adjust view properties
setSideBarWidth(be_plain_font->StringWidth(" Frame Size ") + 2 * InfoView::M_H_MARGIN);
BString s;
// add the "Bit Rate" field
s = MediaString::forVideoBitRate(format.u.encoded_video.avg_bit_rate,
format.u.encoded_video.max_bit_rate);
addField("Bit Rate", s);
// add the "Frame Size" field
s = MediaString::forVideoFrameSize(format.u.encoded_video.frame_size);
addField("Frame Size", s);
// add the "History" field
s = MediaString::forVideoHistory(format.u.encoded_video.forward_history,
format.u.encoded_video.backward_history);
addField("History", s);
break;
}
case B_MEDIA_MULTISTREAM: {
// adjust view properties
setSideBarWidth(be_plain_font->StringWidth(" Chunk Size ") + 2 * InfoView::M_H_MARGIN);
BString s;
// add the "Format" field
s = MediaString::forMultistreamFormat(format.u.multistream.format);
addField("Format", s);
// add the "Bit Rate" field
s = MediaString::forMultistreamBitRate(format.u.multistream.avg_bit_rate,
format.u.multistream.max_bit_rate);
addField("Bit Rate", s);
// add the "Chunk Size" field
s = MediaString::forMultistreamChunkSize(format.u.multistream.avg_chunk_size,
format.u.multistream.max_chunk_size);
addField("Chunk Size", s);
// add the "Flags" field
s = MediaString::forMultistreamFlags(format.u.multistream.flags);
addField("Flags", s);
break;
}
default: {
// add no fields
}
}
}
// -------------------------------------------------------- //
// *** BView implementation (public)
// -------------------------------------------------------- //
void ConnectionInfoView::DetachedFromWindow() {
D_METHOD(("ConnectionInfoView::DetachedFromWindow()\n"));
InfoWindowManager *manager = InfoWindowManager::Instance();
if (manager) {
BMessage message(InfoWindowManager::M_CONNECTION_WINDOW_CLOSED);
message.AddInt32("source_port", m_source.port);
message.AddInt32("source_id", m_source.id);
message.AddInt32("destination_port", m_destination.port);
message.AddInt32("destination_id", m_destination.id);
manager->PostMessage(&message);
}
}
// END -- ConnectionInfoView.cpp --

View File

@ -0,0 +1,54 @@
// ConnectionInfoView.h (Cortex/InfoView)
//
// * PURPOSE
// Display connection-specific info in the InfoWindow.
// This is: source, destination and format.
//
// * HISTORY
// c.lenz 5nov99 Begun
//
#ifndef __ConnectionInfoView_H__
#define __ConnectionInfoView_H__
#include "InfoView.h"
#include <MediaDefs.h>
#include "cortex_defs.h"
__BEGIN_CORTEX_NAMESPACE
// NodeManager
class Connection;
class ConnectionInfoView : public InfoView
{
public: // *** ctor/dtor
ConnectionInfoView(
const Connection &connection);
virtual ~ConnectionInfoView();
private: // *** internal operations
// adds media_format related fields to the view
// (wildcard-aware)
void _addFormatFields(
const media_format &format);
public: // *** BView impl
// notify InfoWindowManager
virtual void DetachedFromWindow();
private: // *** data members
media_source m_source;
media_destination m_destination;
};
__END_CORTEX_NAMESPACE
#endif /* __ConnectionInfoView_H__ */

View File

@ -0,0 +1,137 @@
// DormantNodeInfoView.cpp
#include "DormantNodeInfoView.h"
// InfoView
#include "InfoWindowManager.h"
// Support
#include "MediaIcon.h"
#include "MediaString.h"
// Media Kit
#include <MediaAddOn.h>
#include <MediaRoster.h>
__USE_CORTEX_NAMESPACE
#include <Debug.h>
#define D_METHOD(x) //PRINT (x)
// -------------------------------------------------------- //
// *** ctor/dtor (public)
// -------------------------------------------------------- //
DormantNodeInfoView::DormantNodeInfoView(
const dormant_node_info &info)
: InfoView(info.name, "Dormant Media Node",
new MediaIcon(info, B_LARGE_ICON)),
m_addOnID(info.addon),
m_flavorID(info.flavor_id)
{
D_METHOD(("DormantNodeInfoView::DormantNodeInfoView()\n"));
// adjust view properties
setSideBarWidth(be_plain_font->StringWidth(" Output Formats ") + 2 * InfoView::M_H_MARGIN);
BString s;
// add the "AddOn ID" field
s = "";
s << info.addon;
addField("AddOn ID", s);
// add the "Flavor ID" field
s = "";
s << info.flavor_id;
addField("Flavor ID", s);
// add separator field
addField("", "");
dormant_flavor_info flavorInfo;
BMediaRoster *roster = BMediaRoster::Roster();
if (roster && (roster->GetDormantFlavorInfoFor(info, &flavorInfo) == B_OK))
{
// add the "Description" field
s = flavorInfo.info;
addField("Description", s);
// add "Kinds" field
addField("Kinds", MediaString::getStringFor(static_cast<node_kind>(flavorInfo.kinds)));
// add "Flavor Flags" field
addField("Flavor Flags", "?");
// add "Max Instances" field
if (flavorInfo.possible_count > 0)
{
s = "";
s << flavorInfo.possible_count;
}
else
{
s = "Any number";
}
addField("Max Instances", s);
// add "Input Formats" field
if (flavorInfo.in_format_count > 0)
{
if (flavorInfo.in_format_count == 1)
{
addField("Input Format", MediaString::getStringFor(flavorInfo.in_formats[0], false));
}
else
{
addField("Input Formats", "");
for (int32 i = 0; i < flavorInfo.in_format_count; i++)
{
s = "";
s << "(" << i + 1 << ")";
addField(s, MediaString::getStringFor(flavorInfo.in_formats[i], false));
}
}
}
// add "Output Formats" field
if (flavorInfo.out_format_count > 0)
{
if (flavorInfo.out_format_count == 1)
{
addField("Output Format", MediaString::getStringFor(flavorInfo.out_formats[0], false));
}
else
{
addField("Output Formats", "");
for (int32 i = 0; i < flavorInfo.out_format_count; i++)
{
s = "";
s << "(" << i + 1 << ")";
addField(s, MediaString::getStringFor(flavorInfo.out_formats[i], false));
}
}
}
}
}
DormantNodeInfoView::~DormantNodeInfoView()
{
D_METHOD(("DormantNodeInfoView::~DormantNodeInfoView()\n"));
}
// -------------------------------------------------------- //
// *** BView implementation (public)
// -------------------------------------------------------- //
void DormantNodeInfoView::DetachedFromWindow() {
D_METHOD(("DormantNodeInfoView::DetachedFromWindow()\n"));
InfoWindowManager *manager = InfoWindowManager::Instance();
if (manager) {
BMessage message(InfoWindowManager::M_DORMANT_NODE_WINDOW_CLOSED);
message.AddInt32("addOnID", m_addOnID);
message.AddInt32("flavorID", m_flavorID);
manager->PostMessage(&message);
}
}
// END -- DormantNodeInfoView.cpp --

View File

@ -0,0 +1,48 @@
// DormantNodeInfoView.h (Cortex/InfoView)
//
// * PURPOSE
// An InfoView variant for dormant MediaNodes. Accepts
// a dormant_node_info struct in the constructor and
// tries to aquire the corresponding dormant_flavor_info
// from the BMediaRoster.
//
// * HISTORY
// c.lenz 5nov99 Begun
//
#ifndef __DormantNodeInfoView_H__
#define __DormantNodeInfoView_H__
#include "InfoView.h"
#include "cortex_defs.h"
__BEGIN_CORTEX_NAMESPACE
class NodeRef;
class DormantNodeInfoView :
public InfoView {
public: // *** ctor/dtor
// add fields relevant for dormant MediaNodes (like
// AddOn-ID, input/output formats etc.)
DormantNodeInfoView(
const dormant_node_info &info);
virtual ~DormantNodeInfoView();
public: // *** BView impl
// notify InfoWindowManager
virtual void DetachedFromWindow();
private: // *** data members
int32 m_addOnID;
int32 m_flavorID;
};
__END_CORTEX_NAMESPACE
#endif /* __DormantNodeInfoView_H__ */

View File

@ -0,0 +1,225 @@
// EndPointInfoView.cpp
#include "EndPointInfoView.h"
// InfoView
#include "InfoWindowManager.h"
// Support
#include "MediaIcon.h"
#include "MediaString.h"
__USE_CORTEX_NAMESPACE
#include <Debug.h>
#define D_METHOD(x) //PRINT (x)
// -------------------------------------------------------- //
// *** ctor/dtor (public)
// -------------------------------------------------------- //
EndPointInfoView::EndPointInfoView(
const media_input &input)
: InfoView(input.name, "Media Input", 0),
m_output(false),
m_port(input.destination.port),
m_id(input.destination.id) {
D_METHOD(("EndPointInfoView::EndPointInfoView(input)\n"));
setSideBarWidth(be_plain_font->StringWidth(" Destination ")
+ 2 * InfoView::M_H_MARGIN);
// add "Source" field
addField("Source", MediaString::getStringFor(input.source));
// add "Destination" field
addField("Destination", MediaString::getStringFor(input.destination));
// add a separator field
addField("", "");
// add "Media Type" field
addField("Media Type", MediaString::getStringFor(input.format.type));
_addFormatFields(input.format);
}
EndPointInfoView::EndPointInfoView(
const media_output &output)
: InfoView(output.name, "Media Output", 0),
m_output(true),
m_port(output.source.port),
m_id(output.source.id) {
D_METHOD(("EndPointInfoView::EndPointInfoView(output)\n"));
setSideBarWidth(be_plain_font->StringWidth(" Destination ")
+ 2 * InfoView::M_H_MARGIN);
// add "Source" field
addField("Source", MediaString::getStringFor(output.source));
// add "Destination" field
addField("Destination", MediaString::getStringFor(output.destination));
// add a separator field
addField("", "");
// add "Media Type" field
addField("Media Type", MediaString::getStringFor(output.format.type));
_addFormatFields(output.format);
}
EndPointInfoView::~EndPointInfoView()
{
D_METHOD(("EndPointInfoView::~EndPointInfoView()\n"));
}
// -------------------------------------------------------- //
// *** BView implementation (public)
// -------------------------------------------------------- //
void EndPointInfoView::DetachedFromWindow() {
D_METHOD(("EndPointInfoView::DetachedFromWindow()\n"));
InfoWindowManager *manager = InfoWindowManager::Instance();
if (manager) {
if (m_output) {
BMessage message(InfoWindowManager::M_OUTPUT_WINDOW_CLOSED);
message.AddInt32("source_port", m_port);
message.AddInt32("source_id", m_id);
manager->PostMessage(&message);
}
else {
BMessage message(InfoWindowManager::M_INPUT_WINDOW_CLOSED);
message.AddInt32("destination_port", m_port);
message.AddInt32("destination_id", m_id);
manager->PostMessage(&message);
}
}
}
// -------------------------------------------------------- //
// *** internal operations (private)
// -------------------------------------------------------- //
void EndPointInfoView::_addFormatFields(
const media_format &format)
{
D_METHOD(("EndPointInfoView::_addFormatFields()\n"));
switch (format.type) {
case B_MEDIA_RAW_AUDIO: {
// adjust view properties
setSideBarWidth(be_plain_font->StringWidth(" Sample Rate ") + 2 * InfoView::M_H_MARGIN);
BString s;
// add "Format" field
s = MediaString::forAudioFormat(format.u.raw_audio.format,
format.u.raw_audio.valid_bits);
addField("Format", s);
// add "Sample Rate" field
s = MediaString::forAudioFrameRate(format.u.raw_audio.frame_rate);
addField("Sample Rate", s);
// add "Channels" field
s = MediaString::forAudioChannelCount(format.u.raw_audio.channel_count);
addField("Channels", s);
// add "Channel Mask" field
s = MediaString::forAudioChannelMask(format.u.raw_audio.channel_mask);
addField("Channel Mask", s);
// add "Matrix Mask" field
s = MediaString::forAudioMatrixMask(format.u.raw_audio.matrix_mask);
addField("Matrix Mask", s);
// add the "Byte Order" field
s = MediaString::forAudioByteOrder(format.u.raw_audio.byte_order);
addField("Byte Order", s);
// add the "Buffer Size" field
s = MediaString::forAudioBufferSize(format.u.raw_audio.buffer_size);
addField("Buffer Size", s);
break;
}
case B_MEDIA_RAW_VIDEO: {
// adjust view properties
setSideBarWidth(be_plain_font->StringWidth(" Video Data Between ") + 2 * InfoView::M_H_MARGIN);
BString s;
// add the "Format" field
s = MediaString::forVideoFormat(format.u.raw_video.display.format);
addField("Format", s);
// add the "Resolution" field
s = MediaString::forVideoResolution(format.u.raw_video.display.line_width,
format.u.raw_video.display.line_count);
addField("Resolution", s);
// add the "Field Rate" field
s = MediaString::forVideoFieldRate(format.u.raw_video.field_rate,
format.u.raw_video.interlace);
addField("Field Rate", s);
// add the "Orientation" field
s = MediaString::forVideoOrientation(format.u.raw_video.orientation);
addField("Orientation", s);
// add the "Aspect Ratio" field
s = MediaString::forVideoAspectRatio(format.u.raw_video.pixel_width_aspect,
format.u.raw_video.pixel_height_aspect);
addField("Aspect Ratio", s);
// add the "Active Lines" field
s = MediaString::forVideoActiveLines(format.u.raw_video.first_active,
format.u.raw_video.last_active);
addField("Active Lines", s);
// add the "Offset" field
s = MediaString::forVideoOffset(format.u.raw_video.display.pixel_offset,
format.u.raw_video.display.line_offset);
addField("Offset", s);
break;
}
case B_MEDIA_ENCODED_AUDIO: {
// adjust view properties
setSideBarWidth(be_plain_font->StringWidth(" Frame Size ") + 2 * InfoView::M_H_MARGIN);
BString s;
// add the "Bit Rate" field
s = MediaString::forAudioBitRate(format.u.encoded_audio.bit_rate);
addField("Bit Rate", s);
// add the "Frame Size" field
s = MediaString::forAudioFrameSize(format.u.encoded_audio.frame_size);
addField("Frame Size", s);
break;
}
case B_MEDIA_ENCODED_VIDEO: {
// adjust view properties
setSideBarWidth(be_plain_font->StringWidth(" Frame Size ") + 2 * InfoView::M_H_MARGIN);
BString s;
// add the "Bit Rate" field
s = MediaString::forVideoBitRate(format.u.encoded_video.avg_bit_rate,
format.u.encoded_video.max_bit_rate);
addField("Bit Rate", s);
// add the "Frame Size" field
s = MediaString::forVideoFrameSize(format.u.encoded_video.frame_size);
addField("Frame Size", s);
// add the "History" field
s = MediaString::forVideoHistory(format.u.encoded_video.forward_history,
format.u.encoded_video.backward_history);
addField("History", s);
break;
}
case B_MEDIA_MULTISTREAM: {
// adjust view properties
setSideBarWidth(be_plain_font->StringWidth(" Chunk Size ") + 2 * InfoView::M_H_MARGIN);
BString s;
// add the "Format" field
s = MediaString::forMultistreamFormat(format.u.multistream.format);
addField("Format", s);
// add the "Bit Rate" field
s = MediaString::forMultistreamBitRate(format.u.multistream.avg_bit_rate,
format.u.multistream.max_bit_rate);
addField("Bit Rate", s);
// add the "Chunk Size" field
s = MediaString::forMultistreamChunkSize(format.u.multistream.avg_chunk_size,
format.u.multistream.max_chunk_size);
addField("Chunk Size", s);
// add the "Flags" field
s = MediaString::forMultistreamFlags(format.u.multistream.flags);
addField("Flags", s);
break;
}
default: {
// add no fields
}
}
}
// END -- EndPointInfoView.cpp --

View File

@ -0,0 +1,64 @@
// EndPointInfoView.h (Cortex/InfoView)
//
// * PURPOSE
// Display input/output related info in the InfoWindow.
// Very similar to ConnectionInfoView, only that this
// views is prepared to handle wildcard values in the
// media_format (a connection should never have to!)
//
// * HISTORY
// c.lenz 14nov99 Begun
//
#ifndef __EndPointInfoView_H__
#define __EndPointInfoView_H__
#include "InfoView.h"
// Media Kit
#include <MediaDefs.h>
#include "cortex_defs.h"
__BEGIN_CORTEX_NAMESPACE
class EndPointInfoView :
public InfoView {
public: // *** ctor/dtor
// creates an InfoView for a media_input. adds source
// and destination fields, then calls _addFormatFields
EndPointInfoView(
const media_input &input);
// creates an InfoView for a media_output. adds source
// and destination fields, then calls _addFormatFields
EndPointInfoView(
const media_output &output);
virtual ~EndPointInfoView();
public: // *** BView impl
// notify InfoWindowManager
virtual void DetachedFromWindow();
private: // *** internal operations
// adds media_format related fields to the view
// (wildcard-aware)
void _addFormatFields(
const media_format &format);
private: // *** data members
// true if media_output
bool m_output;
int32 m_port;
int32 m_id;
};
__END_CORTEX_NAMESPACE
#endif /* __EndPointInfoView_H__ */

View File

@ -0,0 +1,135 @@
// FileNodeInfoView.cpp
#include "FileNodeInfoView.h"
#include "MediaIcon.h"
#include "MediaString.h"
#include "NodeRef.h"
#include <MediaFile.h>
#include <MediaNode.h>
#include <MediaRoster.h>
#include <MediaTrack.h>
#include <TimeCode.h>
__USE_CORTEX_NAMESPACE
#include <Debug.h>
#define D_METHOD(x) //PRINT (x)
// -------------------------------------------------------- //
// *** ctor/dtor (public)
// -------------------------------------------------------- //
FileNodeInfoView::FileNodeInfoView(
const NodeRef *ref)
: LiveNodeInfoView(ref)
{
D_METHOD(("FileNodeInfoView::FileNodeInfoView()\n"));
// adjust view properties
setSideBarWidth(be_plain_font->StringWidth(" File Format ") + 2 * InfoView::M_H_MARGIN);
setSubTitle("Live File-Interface Node");
// if a ref is set for this file-interface display some info
// thru MediaFile and set the title appropriatly
BString title;
BString s;
entry_ref nodeFile;
status_t error;
error = BMediaRoster::Roster()->GetRefFor(ref->node(), &nodeFile);
if (!error)
{
BMediaFile file(&nodeFile);
if (file.InitCheck() == B_OK)
{
// add separator field
addField("", "");
// add "File Format" fields
media_file_format format;
if (file.GetFileFormatInfo(&format) == B_OK)
{
s = "";
s << format.pretty_name << " (" << format.mime_type << ")";
addField("File Format", s);
}
// add "Copyright" field
const char *copyRight = file.Copyright();
if (copyRight)
{
s = copyRight;
addField("Copyright", s);
}
// add "Tracks" list
if (file.CountTracks() > 0)
{
addField("Tracks", "");
for (int32 i = 0; i < file.CountTracks(); i++)
{
BString label;
label << "(" << i + 1 << ")";
BMediaTrack *track = file.TrackAt(i);
// add format
media_format format;
if (track->EncodedFormat(&format) == B_OK)
{
s = MediaString::getStringFor(format, false);
}
if ((format.type == B_MEDIA_ENCODED_AUDIO)
|| (format.type == B_MEDIA_ENCODED_VIDEO))
{
// add codec
media_codec_info codec;
if (track->GetCodecInfo(&codec) == B_OK)
{
s << "\n- Codec: " << codec.pretty_name;
if (codec.id > 0)
{
s << " (ID: " << codec.id << ")";
}
}
}
// add duration
bigtime_t duration = track->Duration();
int hours, minutes, seconds, frames;
us_to_timecode(duration, &hours, &minutes, &seconds, &frames);
char buffer[64];
sprintf(buffer, "%02d:%02d:%02d:%02d", hours, minutes, seconds, frames);
s << "\n- Duration: " << buffer;
// add quality
float quality;
if (track->GetQuality(&quality) == B_OK)
{
s << "\n- Quality: " << quality;
}
addField(label, s);
}
}
}
// set title
BEntry entry(&nodeFile);
char fileName[B_FILE_NAME_LENGTH];
entry.GetName(fileName);
title = fileName;
}
else
{
// set title
title = ref->name();
title += " (no file)";
}
setTitle(title);
}
FileNodeInfoView::~FileNodeInfoView()
{
D_METHOD(("FileNodeInfoView::~FileNodeInfoView()\n"));
}
// END -- FileNodeInfoView.cpp --

View File

@ -0,0 +1,36 @@
// FileNodeInfoView.h (Cortex/InfoView)
//
// * PURPOSE
// In addition to the fields defined by its base class
// LiveNodeInfoView, this class defines media-file specific
// fields, line number of tracks, codecs, formats, etc.
//
// * HISTORY
// c.lenz 13nov99 Begun
//
#ifndef __FileNodeInfoView_H__
#define __FileNodeInfoView_H__
#include "LiveNodeInfoView.h"
#include "cortex_defs.h"
__BEGIN_CORTEX_NAMESPACE
class NodeRef;
class FileNodeInfoView : public LiveNodeInfoView
{
public: // *** ctor/dtor
// add file related fields to the view by creating
// and querying an instance of BMediaFile/BMediaTrack
FileNodeInfoView(
const NodeRef *ref);
virtual ~FileNodeInfoView();
};
__END_CORTEX_NAMESPACE
#endif /* __FileNodeInfoView_H__ */

View File

@ -0,0 +1,586 @@
// InfoView.cpp
#include "InfoView.h"
#include "cortex_ui.h"
#include "array_delete.h"
// Interface Kit
#include <Bitmap.h>
#include <Region.h>
#include <ScrollBar.h>
#include <StringView.h>
#include <TextView.h>
#include <Window.h>
// Storage Kit
#include <Mime.h>
// Support Kit
#include <List.h>
__USE_CORTEX_NAMESPACE
#include <Debug.h>
#define D_ALLOC(X) //PRINT (x) // ctor/dtor
#define D_HOOK(X) //PRINT (x) // BView impl.
#define D_ACCESS(X) //PRINT (x) // Accessors
#define D_METHOD(x) //PRINT (x)
// -------------------------------------------------------- //
// *** internal class: _InfoTextField
//
// * PURPOSE:
// store the label & text for each field, and provide methods
// for linewrapping and drawing
//
// -------------------------------------------------------- //
class _InfoTextField
{
public: // *** ctor/dtor
_InfoTextField(
BString label,
BString text,
InfoView *parent);
~_InfoTextField();
public: // *** operations
void drawField(
BPoint position);
void updateLineWrapping(
bool *wrappingChanged = 0,
bool *heightChanged = 0);
public: // *** accessors
float getHeight() const;
float getWidth() const;
bool isWrapped() const;
private: // *** static internal methods
static bool canEndLine(
const char c);
static bool mustEndLine(
const char c);
private: // *** data members
BString m_label;
BString m_text;
BList *m_textLines;
InfoView *m_parent;
};
// -------------------------------------------------------- //
// *** static member init
// -------------------------------------------------------- //
const BRect InfoView::M_DEFAULT_FRAME = BRect(0.0, 0.0, 250.0, 100.0);
const float InfoView::M_H_MARGIN = 5.0;
const float InfoView::M_V_MARGIN = 5.0;
// -------------------------------------------------------- //
// *** ctor/dtor (public)
// -------------------------------------------------------- //
InfoView::InfoView(
BString title,
BString subTitle,
BBitmap *icon)
: BView(M_DEFAULT_FRAME, "InfoView", B_FOLLOW_ALL_SIDES,
B_WILL_DRAW | B_FRAME_EVENTS),
m_title(title),
m_subTitle(subTitle),
m_icon(0),
m_fields(0) {
D_ALLOC(("InfoView::InfoView()\n"));
if (icon) {
m_icon = new BBitmap(icon);
}
m_fields = new BList();
SetViewColor(B_TRANSPARENT_COLOR);
}
InfoView::~InfoView() {
D_ALLOC(("InfoView::~InfoView()\n"));
// delete all the fields
if (m_fields) {
while (m_fields->CountItems() > 0) {
_InfoTextField *field = static_cast<_InfoTextField *>
(m_fields->RemoveItem((int32)0));
if (field) {
delete field;
}
}
delete m_fields;
m_fields = 0;
}
// delete the icon bitmap
if (m_icon) {
delete m_icon;
m_icon = 0;
}
}
// -------------------------------------------------------- //
// *** BView implementation
// -------------------------------------------------------- //
void InfoView::AttachedToWindow() {
D_HOOK(("InfoView::AttachedToWindow()\n"));
// adjust the windows title
BString title = m_title;
title << " info";
Window()->SetTitle(title.String());
// calculate the area occupied by title, subtitle and icon
font_height fh;
be_bold_font->GetHeight(&fh);
float titleHeight = fh.leading + fh.descent;
titleHeight += M_V_MARGIN * 2.0 + B_LARGE_ICON / 2.0;
be_plain_font->GetHeight(&fh);
titleHeight += fh.leading + fh.ascent + fh.descent;
BFont font(be_bold_font);
float titleWidth = font.StringWidth(title.String());
titleWidth += M_H_MARGIN + B_LARGE_ICON + B_LARGE_ICON / 2.0;
float width, height;
GetPreferredSize(&width, &height);
Window()->ResizeTo(width + B_V_SCROLL_BAR_WIDTH, height);
ResizeBy(- B_V_SCROLL_BAR_WIDTH, 0.0);
// add scroll bar
BRect scrollRect = Window()->Bounds();
scrollRect.left = scrollRect.right - B_V_SCROLL_BAR_WIDTH + 1.0;
scrollRect.top -= 1.0;
scrollRect.right += 1.0;
scrollRect.bottom -= B_H_SCROLL_BAR_HEIGHT - 1.0;
Window()->AddChild(new BScrollBar(scrollRect, "ScrollBar", this,
0.0, 0.0, B_VERTICAL));
ScrollBar(B_VERTICAL)->SetRange(0.0, 0.0);
be_plain_font->GetHeight(&fh);
float step = fh.ascent + fh.descent + fh.leading + M_V_MARGIN;
ScrollBar(B_VERTICAL)->SetSteps(step, step * 5);
// set window size limits
float minWidth, maxWidth, minHeight, maxHeight;
Window()->GetSizeLimits(&minWidth, &maxWidth, &minHeight, &maxHeight);
Window()->SetSizeLimits(titleWidth + B_V_SCROLL_BAR_WIDTH, maxWidth,
titleHeight + B_H_SCROLL_BAR_HEIGHT, maxHeight);
// cache the bounds rect for proper redraw later on...
m_oldFrame = Bounds();
}
void InfoView::Draw(
BRect updateRect) {
D_HOOK(("InfoView::Draw()\n"));
// Draw side bar
SetDrawingMode(B_OP_COPY);
BRect r = Bounds();
r.right = B_LARGE_ICON - 1.0;
SetLowColor(M_LIGHT_BLUE_COLOR);
FillRect(r, B_SOLID_LOW);
SetHighColor(M_DARK_BLUE_COLOR);
r.right += 1.0;
StrokeLine(r.RightTop(), r.RightBottom(), B_SOLID_HIGH);
// Draw background
BRegion region;
region.Include(updateRect);
region.Exclude(r);
SetLowColor(M_GRAY_COLOR);
FillRegion(&region, B_SOLID_LOW);
// Draw title
SetDrawingMode(B_OP_OVER);
font_height fh;
be_bold_font->GetHeight(&fh);
SetFont(be_bold_font);
BPoint p(M_H_MARGIN + B_LARGE_ICON + B_LARGE_ICON / 2.0,
M_V_MARGIN * 2.0 + fh.ascent);
SetHighColor(M_BLACK_COLOR);
DrawString(m_title.String(), p);
// Draw sub-title
p.y += fh.descent;
be_plain_font->GetHeight(&fh);
SetFont(be_plain_font);
p.y += fh.ascent + fh.leading;
SetHighColor(M_DARK_GRAY_COLOR);
DrawString(m_subTitle.String(), p);
// Draw icon
p.y = 2 * M_V_MARGIN;
if (m_icon) {
p.x = B_LARGE_ICON / 2.0;
DrawBitmapAsync(m_icon, p);
}
// Draw fields
be_plain_font->GetHeight(&fh);
p.x = B_LARGE_ICON;
p.y += B_LARGE_ICON + 2 * M_V_MARGIN + fh.ascent + 2 * fh.leading;
for (int32 i = 0; i < m_fields->CountItems(); i++) {
_InfoTextField *field = static_cast<_InfoTextField *>(m_fields->ItemAt(i));
field->drawField(p);
p.y += field->getHeight() + M_V_MARGIN;
}
}
void InfoView::FrameResized(
float width,
float height) {
D_HOOK(("InfoView::FrameResized()\n"));
BRect newFrame = BRect(0.0, 0.0, width, height);
// update the each lines' line-wrapping and redraw as necessary
font_height fh;
BPoint p;
be_plain_font->GetHeight(&fh);
p.x = B_LARGE_ICON;
p.y += B_LARGE_ICON + M_V_MARGIN * 2.0 + fh.ascent + fh.leading * 2.0;
bool heightChanged = false;
for (int32 i = 0; i < m_fields->CountItems(); i++) {
bool wrappingChanged = false;
_InfoTextField *field = static_cast<_InfoTextField *>(m_fields->ItemAt(i));
field->updateLineWrapping(&wrappingChanged,
heightChanged ? 0 : &heightChanged);
float fieldHeight = field->getHeight() + M_V_MARGIN;
if (heightChanged) {
Invalidate(BRect(p.x, p.y, width, p.y + fieldHeight));
}
else if (wrappingChanged) {
Invalidate(BRect(p.x + m_sideBarWidth, p.y, width, p.y + fieldHeight));
}
p.y += fieldHeight;
}
// clean up the rest of the view
BRect updateRect;
updateRect.left = B_LARGE_ICON;
updateRect.top = p.y < (m_oldFrame.bottom - M_V_MARGIN - 15.0) ?
p.y - 15.0 : m_oldFrame.bottom - M_V_MARGIN - 15.0;
updateRect.right = width - M_H_MARGIN;
updateRect.bottom = m_oldFrame.bottom < newFrame.bottom ?
newFrame.bottom : m_oldFrame.bottom;
Invalidate(updateRect);
if (p.y > height) {
ScrollBar(B_VERTICAL)->SetRange(0.0, ceil(p.y - height));
}
else {
ScrollBar(B_VERTICAL)->SetRange(0.0, 0.0);
}
// cache the new frame rect for the next time
m_oldFrame = newFrame;
}
void
InfoView::GetPreferredSize(
float *width,
float *height) {
D_HOOK(("InfoView::GetPreferredSize()\n"));
*width = 0;
*height = 0;
// calculate the height needed to display everything, avoiding line wrapping
font_height fh;
be_plain_font->GetHeight(&fh);
for (int32 i = 0; i < m_fields->CountItems(); i++) {
_InfoTextField *field = static_cast<_InfoTextField *>(m_fields->ItemAt(i));
*height += fh.ascent + fh.descent + fh.leading + M_V_MARGIN;
float tfw = field->getWidth();
if (tfw > *width) {
*width = tfw;
}
}
*width += B_LARGE_ICON + 2 * M_H_MARGIN;
*height += B_LARGE_ICON + 2 * M_V_MARGIN + fh.ascent + 2 * fh.leading;
*height += B_H_SCROLL_BAR_HEIGHT;
}
// -------------------------------------------------------- //
// *** operations (protected)
// -------------------------------------------------------- //
void InfoView::addField(
BString label,
BString text) {
D_METHOD(("InfoView::addField()\n"));
m_fields->AddItem(reinterpret_cast<void *>
(new _InfoTextField(label, text, this)));
}
// -------------------------------------------------------- //
// *** internal class: _InfoTextField
//
// *** ctor/dtor
// -------------------------------------------------------- //
_InfoTextField::_InfoTextField(
BString label,
BString text,
InfoView *parent)
: m_label(label),
m_text(text),
m_textLines(0),
m_parent(parent) {
D_ALLOC(("_InfoTextField::_InfoTextField()\n"));
if (m_label != "") {
m_label << ": ";
}
m_textLines = new BList();
}
_InfoTextField::~_InfoTextField() {
D_ALLOC(("_InfoTextField::~_InfoTextField()\n"));
// delete every line
if (m_textLines) {
while (m_textLines->CountItems() > 0) {
BString *line = static_cast<BString *>(m_textLines->RemoveItem((int32)0));
if (line) {
delete line;
}
}
delete m_textLines;
m_textLines = 0;
}
}
// -------------------------------------------------------- //
// *** internal class: _InfoTextField
//
// *** operations (public)
// -------------------------------------------------------- //
void _InfoTextField::drawField(
BPoint position) {
D_METHOD(("_InfoTextField::drawField()\n"));
float sideBarWidth = m_parent->getSideBarWidth();
// Draw label
BPoint p = position;
p.x += sideBarWidth - be_plain_font->StringWidth(m_label.String());
m_parent->SetHighColor(M_DARK_GRAY_COLOR);
m_parent->SetDrawingMode(B_OP_OVER);
m_parent->SetFont(be_plain_font);
m_parent->DrawString(m_label.String(), p);
// Draw text
font_height fh;
be_plain_font->GetHeight(&fh);
p.x = position.x + sideBarWidth;// + InfoView::M_H_MARGIN;
m_parent->SetHighColor(M_BLACK_COLOR);
for (int32 i = 0; i < m_textLines->CountItems(); i++) {
BString *line = static_cast<BString *>(m_textLines->ItemAt(i));
m_parent->DrawString(line->String(), p);
p.y += fh.ascent + fh.descent + fh.leading;
}
}
void _InfoTextField::updateLineWrapping(
bool *wrappingChanged,
bool *heightChanged)
{
D_METHOD(("_InfoTextField::updateLineWrapping()\n"));
// clear the current list of lines but remember their number and
// the number of characters per line (to know if something changed)
int32 numLines = m_textLines->CountItems();
int32* numChars = new int32[numLines];
array_delete<int32> _d(numChars);
for (int32 i = 0; i < numLines; i++)
{
BString *line = static_cast<BString *>(m_textLines->ItemAt(i));
numChars[i] = line->CountChars();
delete line;
}
m_textLines->MakeEmpty();
// calculate the maximum width for a line
float maxWidth = m_parent->Bounds().Width();
maxWidth -= m_parent->getSideBarWidth() + 3 * InfoView::M_H_MARGIN + B_LARGE_ICON;
if (maxWidth <= be_plain_font->StringWidth("M"))
{
return;
}
// iterate through the text and split into new lines as
// necessary
BString *currentLine = new BString(m_text);
while (currentLine && (currentLine->CountChars() > 0))
{
int32 lastBreak = 0;
for (int32 i = 0; i < currentLine->CountChars(); i++)
{
if (canEndLine(currentLine->ByteAt(i)))
{
lastBreak = i + 1;
if (mustEndLine(currentLine->ByteAt(i)))
{
BString *newLine = new BString();
currentLine->Remove(i, 1);
currentLine->MoveInto(*newLine, i,
currentLine->CountChars() - i);
m_textLines->AddItem(reinterpret_cast<void *>(currentLine));
currentLine = newLine;
break;
}
}
else
{
if (i == currentLine->CountChars() - 1) // the last char in the text
{
m_textLines->AddItem(reinterpret_cast<void *>(currentLine));
currentLine = 0;
break;
}
else
{
BString buffer;
currentLine->CopyInto(buffer, 0, i);
if (be_plain_font->StringWidth(buffer.String()) > maxWidth)
{
if (lastBreak < 1)
{
lastBreak = i - 1;
}
BString *newLine = new BString();
currentLine->MoveInto(*newLine, lastBreak,
currentLine->CountChars() - lastBreak);
m_textLines->AddItem(reinterpret_cast<void *>(currentLine));
currentLine = newLine;
break;
}
}
}
}
}
// report changes in the fields total height (i.e. if the number
// of lines changed)
if (heightChanged && (numLines != m_textLines->CountItems()))
{
*heightChanged = true;
}
// report changes in the wrapping (e.g. if a word slipped into the
// next line)
else if (wrappingChanged)
{
for (int32 i = 0; i < m_textLines->CountItems(); i++)
{
BString *line = static_cast<BString *>(m_textLines->ItemAt(i));
if (line->CountChars() != numChars[i])
{
*wrappingChanged = true;
break;
}
}
}
}
// -------------------------------------------------------- //
// *** internal class: _InfoTextField
//
// *** accessors (public)
// -------------------------------------------------------- //
float
_InfoTextField::getHeight() const {
D_ACCESS(("_InfoTextField::getHeight()\n"));
font_height fh;
be_plain_font->GetHeight(&fh);
// calculate the width for an empty line (separator)
if (m_textLines->CountItems() == 0)
{
return fh.ascent + fh.descent + fh.leading;
}
// calculate the total height of the field by counting the
else
{
float height = fh.ascent + fh.descent + fh.leading;
height *= m_textLines->CountItems();
height += fh.leading;
return height;
}
}
float
_InfoTextField::getWidth() const {
D_ACCESS(("_InfoTextField::getWidth()\n"));
float width = be_plain_font->StringWidth(m_text.String());
width += m_parent->getSideBarWidth();
return width;
}
bool
_InfoTextField::isWrapped() const {
D_ACCESS(("_InfoTextField::isWrapped()\n"));
return (m_textLines->CountItems() > 1);
}
// -------------------------------------------------------- //
// *** internal class: _InfoTextField
//
// *** static internal methods (private)
// -------------------------------------------------------- //
bool _InfoTextField::canEndLine(
const char c)
{
D_METHOD(("_InfoTextField::canEndLine()\n"));
if ((c == B_SPACE) || (c == B_TAB) || (c == B_ENTER)
|| ( c == '-'))
{
return true;
}
return false;
}
bool _InfoTextField::mustEndLine(
const char c)
{
D_METHOD(("_InfoTextField::mustEndLine()\n"));
if (c == B_ENTER)
{
return true;
}
return false;
}
// END -- InfoView.cpp --

View File

@ -0,0 +1,139 @@
// InfoView.h (Cortex/InfoView)
//
// * PURPOSE
// A base class for displaying info in a list of fields,
// where each field has a label and the actual content text.
// This class has to be subclassed for providing info on
// specific objects, by adding fields to the view in the
// constructor of the subclass. InfoView takes care of all
// the display details, dynamically rearranging text on resize
// if necessary.
//
// * TODO
// Maybe add more field types, e.g. for options (checkboxes) or
// dropdown-menus ?
//
// * HISTORY
// c.lenz 5nov99 Begun
//
#ifndef __InfoView_H__
#define __InfoView_H__
// Interface Kit
#include <View.h>
// Support Kit
#include <String.h>
#include "cortex_defs.h"
__BEGIN_CORTEX_NAMESPACE
class InfoView :
public BView {
public: // *** constants
// the default frame for an InfoView. Is not actually
// needed right now, because the frame is set to an
// 'ideal' size when the view is attached to the window
static const BRect M_DEFAULT_FRAME;
// defines how much space is used to separate objects
// horizontally
static const float M_H_MARGIN;
// defines how much space is used to separate objects
// vertically
static const float M_V_MARGIN;
public: // *** ctor/dtor
// creates a view containing only the title and subtitle
// and the icon (if provided). No fields are defined here.
InfoView(
BString title,
BString subTitle,
BBitmap *icon);
virtual ~InfoView();
public: // *** BView impl.
// resizes the view to an 'ideal' size and inits linewrapping
// for each field
virtual void AttachedToWindow();
// updates every fields linewrapping
virtual void FrameResized(
float width,
float height);
// returns the ideal size needed to display all text without
// wrapping lines
virtual void GetPreferredSize(
float *width,
float *height);
// draws the title, subtitle, sidebar & icon as well as
// every field
virtual void Draw(
BRect updateRect);
public: // *** accessors
// adjusts the sidebars' width
void setSideBarWidth(
float width)
{ m_sideBarWidth = width; }
// returns the sidebars' width
float getSideBarWidth() const
{ return m_sideBarWidth; }
// set the title (also used for window title)
void setTitle(
BString title)
{ m_title = title; }
// set the string which will be displayed just below
// the title
void setSubTitle(
BString subTitle)
{ m_subTitle = subTitle; }
protected: // *** operations
// add a field with the given label and 'content'-text.
// fields are displayed in the order they are added!
// as there is no way to update the fields (yet), these
// should always be added in the constructor of the
// subclass!
void addField(
BString label,
BString text);
private: // *** data members
// the objects title, which will appear at top of the view
// and in the windows titlebar
BString m_title;
// a string to be displayed right beneath the title, using a
// smaller font
BString m_subTitle;
// an icon representation of the object
BBitmap *m_icon;
// a list of the InfoTextField objects registered thru addField()
BList *m_fields;
// the width of the sidebar holding label strings
float m_sideBarWidth;
// cached frame rect for proper redrawing of the sidebar
BRect m_oldFrame;
};
__END_CORTEX_NAMESPACE
#endif /* __InfoView_H__ */

View File

@ -0,0 +1,139 @@
// InfoWindow.cpp
#include "InfoWindow.h"
// Interface Kit
#include <Screen.h>
#include <ScrollBar.h>
#include <View.h>
__USE_CORTEX_NAMESPACE
#include <Debug.h>
#define D_ALLOC(x) //PRINT (x)
#define D_HOOK(x) //PRINT (x)
#define D_INTERNAL(x) //PRINT (x)
#define D_MESSAGE(x) //PRINT (x)
// -------------------------------------------------------- //
// ctor/dtor
// -------------------------------------------------------- //
InfoWindow::InfoWindow(
BRect frame)
: BWindow(frame,
"", B_DOCUMENT_WINDOW, 0),
m_zoomed(false),
m_zooming(false) {
D_ALLOC(("InfoWindow::InfoWindow()\n"));
}
InfoWindow::~InfoWindow() {
D_ALLOC(("InfoWindow::~InfoWindow()\n"));
}
// -------------------------------------------------------- //
// BWindow impl
// -------------------------------------------------------- //
void
InfoWindow::FrameResized(
float width,
float height) {
D_HOOK(("InfoWindow::FrameResized()\n"));
if (!m_zooming) {
m_zoomed = false;
}
else {
m_zooming = false;
}
}
void
InfoWindow::Show() {
D_HOOK(("InfoWindow::Show()\n"));
_constrainToScreen();
m_manualSize = Bounds().OffsetToCopy(0.0, 0.0);
BWindow::Show();
}
void
InfoWindow::Zoom(
BPoint origin,
float width,
float height) {
D_HOOK(("InfoWindow::Zoom()\n"));
m_zooming = true;
BScreen screen(this);
if (!screen.Frame().Contains(Frame())) {
m_zoomed = false;
}
if (!m_zoomed) {
// resize to the ideal size
m_manualSize = Bounds();
float width, height;
FindView("InfoView")->GetPreferredSize(&width, &height);
width += B_V_SCROLL_BAR_WIDTH;
ResizeTo(width, height);
_constrainToScreen();
m_zoomed = true;
}
else {
// resize to the most recent manual size
ResizeTo(m_manualSize.Width(), m_manualSize.Height());
m_zoomed = false;
}
}
// -------------------------------------------------------- //
// internal operations
// -------------------------------------------------------- //
void
InfoWindow::_constrainToScreen() {
D_INTERNAL(("InfoWindow::_constrainToScreen()\n"));
BScreen screen(this);
BRect screenRect = screen.Frame();
BRect windowRect = Frame();
// if the window is outside the screen rect
// move it to the default position
if (!screenRect.Intersects(windowRect)) {
windowRect.OffsetTo(screenRect.LeftTop());
MoveTo(windowRect.LeftTop());
windowRect = Frame();
}
// if the window is larger than the screen rect
// resize it to fit at each side
if (!screenRect.Contains(windowRect)) {
if (windowRect.left < screenRect.left) {
windowRect.left = screenRect.left + 5.0;
MoveTo(windowRect.LeftTop());
windowRect = Frame();
}
if (windowRect.top < screenRect.top) {
windowRect.top = screenRect.top + 5.0;
MoveTo(windowRect.LeftTop());
windowRect = Frame();
}
if (windowRect.right > screenRect.right) {
windowRect.right = screenRect.right - 5.0;
}
if (windowRect.bottom > screenRect.bottom) {
windowRect.bottom = screenRect.bottom - 5.0;
}
ResizeTo(windowRect.Width(), windowRect.Height());
}
}
// END -- InfoWindow.cpp --

View File

@ -0,0 +1,61 @@
// InfoWindow.h (Cortex/InfoView)
//
// * PURPOSE
//
// * HISTORY
// c.lenz 25may00 Begun
//
#ifndef __InfoWindow_H__
#define __InfoWindow_H__
// Interface Kit
#include <Window.h>
#include "cortex_defs.h"
__BEGIN_CORTEX_NAMESPACE
class InfoWindow :
public BWindow {
public: // *** ctor/dtor
InfoWindow(
BRect frame);
virtual ~InfoWindow();
public: // *** BWindow impl
// remember that frame was changed manually
virtual void FrameResized(
float width,
float height);
// extends BWindow implementation to constrain to screen
// and remember the initial size
virtual void Show();
// extend basic Zoom() functionality to 'minimize' the
// window when currently at max size
virtual void Zoom(
BPoint origin,
float width,
float height);
private: // *** internal operations
// resizes the window to fit in the current screen rect
void _constrainToScreen();
private: // *** data members
BRect m_manualSize;
bool m_zoomed;
bool m_zooming;
};
__END_CORTEX_NAMESPACE
#endif /* __InfoWindow_H__ */

View File

@ -0,0 +1,905 @@
// InfoWindowManager.cpp
#include "InfoWindowManager.h"
// InfoWindow
#include "AppNodeInfoView.h"
#include "ConnectionInfoView.h"
#include "DormantNodeInfoView.h"
#include "EndPointInfoView.h"
#include "FileNodeInfoView.h"
#include "LiveNodeInfoView.h"
#include "InfoWindow.h"
// NodeManager
#include "AddOnHostProtocol.h"
#include "Connection.h"
#include "NodeRef.h"
// Application Kit
#include <Application.h>
#include <AppDefs.h>
#include <Roster.h>
// Media Kit
#include <MediaAddOn.h>
#include <MediaRoster.h>
// Support Kit
#include <List.h>
__USE_CORTEX_NAMESPACE
#include <Debug.h>
#define D_ACCESS(x) //PRINT (x)
#define D_ALLOC(x) //PRINT (x)
#define D_INTERNAL(x) //PRINT (x)
#define D_MESSAGE(x) //PRINT (x)
#define D_WINDOW(x) //PRINT (x)
// -------------------------------------------------------- //
// internal types
// -------------------------------------------------------- //
// used to remember window for live nodes
struct live_node_window {
public: // *** ctor/dtor
live_node_window(
const NodeRef *ref,
BWindow *window)
: ref(ref),
window(window)
{ }
public: // *** data members
const NodeRef *ref;
BWindow *window;
};
// used to remember windows for dormant nodes
struct dormant_node_window {
public: // *** ctor/dtor
dormant_node_window(
const dormant_node_info &info,
BWindow *window)
: info(info),
window(window)
{ }
public: // *** data members
const dormant_node_info info;
BWindow *window;
};
// used to remember windows for connections
struct connection_window {
public: // *** ctor/dtor
connection_window(
const media_source &source,
const media_destination &destination,
BWindow *window)
: source(source),
destination(destination),
window(window)
{ }
public: // *** data members
media_source source;
media_destination destination;
BWindow *window;
};
// used to remember windows for media_inputs
struct input_window {
public: // *** ctor/dtor
input_window(
const media_destination &destination,
BWindow *window)
: destination(destination),
window(window)
{ }
public: // *** data members
media_destination destination;
BWindow *window;
};
// used to remember windows for media_outputs
struct output_window {
public: // *** ctor/dtor
output_window(
const media_source &source,
BWindow *window)
: source(source),
window(window)
{ }
public: // *** data members
media_source source;
BWindow *window;
};
// -------------------------------------------------------- //
// static member init
// -------------------------------------------------------- //
const BPoint InfoWindowManager::M_DEFAULT_OFFSET = BPoint(20.0, 20.0);
const BPoint InfoWindowManager::M_INIT_POSITION = BPoint(90.0, 90.0);
InfoWindowManager *InfoWindowManager::s_instance = 0;
// -------------------------------------------------------- //
// *** ctor/dtor
// -------------------------------------------------------- //
/* hidden */
InfoWindowManager::InfoWindowManager()
: BLooper("InfoWindowManager",
B_NORMAL_PRIORITY),
m_liveNodeWindows(0),
m_dormantNodeWindows(0),
m_connectionWindows(0),
m_inputWindows(0),
m_outputWindows(0),
m_nextWindowPosition(M_INIT_POSITION) {
D_ALLOC(("InfoWindowManager::InfoWindowManager()\n"));
Run();
BMediaRoster *roster = BMediaRoster::CurrentRoster();
if (roster) {
roster->StartWatching(BMessenger(0, this),
B_MEDIA_CONNECTION_BROKEN);
}
}
InfoWindowManager::~InfoWindowManager() {
D_ALLOC(("InfoWindowManager::~InfoWindowManager()\n"));
BMediaRoster *roster = BMediaRoster::CurrentRoster();
if (roster) {
roster->StopWatching(BMessenger(0, this),
B_MEDIA_CONNECTION_BROKEN);
}
if (m_liveNodeWindows) {
while (m_liveNodeWindows->CountItems() > 0) {
live_node_window *entry = static_cast<live_node_window *>
(m_liveNodeWindows->ItemAt(0));
if (entry && entry->window) {
remove_observer(this, entry->ref);
BMessenger messenger(0, entry->window);
messenger.SendMessage(B_QUIT_REQUESTED);
}
m_liveNodeWindows->RemoveItem(reinterpret_cast<void *>(entry));
delete entry;
}
delete m_liveNodeWindows;
m_liveNodeWindows = 0;
}
if (m_dormantNodeWindows) {
while (m_dormantNodeWindows->CountItems() > 0) {
dormant_node_window *entry = static_cast<dormant_node_window *>
(m_dormantNodeWindows->ItemAt(0));
if (entry && entry->window) {
BMessenger messenger(0, entry->window);
messenger.SendMessage(B_QUIT_REQUESTED);
}
m_dormantNodeWindows->RemoveItem(reinterpret_cast<void *>(entry));
delete entry;
}
delete m_dormantNodeWindows;
m_dormantNodeWindows = 0;
}
if (m_connectionWindows) {
while (m_connectionWindows->CountItems() > 0) {
connection_window *entry = static_cast<connection_window *>
(m_connectionWindows->ItemAt(0));
if (entry && entry->window) {
BMessenger messenger(0, entry->window);
messenger.SendMessage(B_QUIT_REQUESTED);
}
m_connectionWindows->RemoveItem(reinterpret_cast<void *>(entry));
delete entry;
}
delete m_connectionWindows;
m_connectionWindows = 0;
}
if (m_inputWindows) {
while (m_inputWindows->CountItems() > 0) {
input_window *entry = static_cast<input_window *>
(m_inputWindows->ItemAt(0));
if (entry && entry->window) {
BMessenger messenger(0, entry->window);
messenger.SendMessage(B_QUIT_REQUESTED);
}
m_inputWindows->RemoveItem(reinterpret_cast<void *>(entry));
delete entry;
}
delete m_inputWindows;
m_inputWindows = 0;
}
if (m_outputWindows) {
while (m_outputWindows->CountItems() > 0) {
output_window *entry = static_cast<output_window *>
(m_outputWindows->ItemAt(0));
if (entry && entry->window) {
BMessenger messenger(0, entry->window);
messenger.SendMessage(B_QUIT_REQUESTED);
}
m_outputWindows->RemoveItem(reinterpret_cast<void *>(entry));
delete entry;
}
delete m_outputWindows;
m_outputWindows = 0;
}
}
// -------------------------------------------------------- //
// *** singleton access
// -------------------------------------------------------- //
/*static*/
InfoWindowManager *InfoWindowManager::Instance() {
D_ACCESS(("InfoWindowManager::Instance()\n"));
if (!s_instance) {
D_ACCESS((" -> create instance\n"));
s_instance = new InfoWindowManager();
}
return s_instance;
}
/* static */
void InfoWindowManager::shutDown() {
D_WINDOW(("InfoWindowManager::shutDown()\n"));
if (s_instance) {
s_instance->Lock();
s_instance->Quit();
s_instance = 0;
}
}
// -------------------------------------------------------- //
// *** operations
// -------------------------------------------------------- //
status_t InfoWindowManager::openWindowFor(
const NodeRef *ref) {
D_WINDOW(("InfoWindowManager::openWindowFor(live_node)\n"));
// make absolutely sure we're locked
if (!IsLocked()) {
debugger("The looper must be locked !");
}
// make sure the ref is valid
if (!ref) {
return B_ERROR;
}
BWindow *window = 0;
if (_findWindowFor(ref->id(), &window)) {
// window for this node already exists, activate it
window->SetWorkspaces(B_CURRENT_WORKSPACE);
window->Activate();
return B_OK;
}
BRect frame = InfoView::M_DEFAULT_FRAME;
frame.OffsetTo(m_nextWindowPosition);
m_nextWindowPosition += M_DEFAULT_OFFSET;
window = new InfoWindow(frame);
if (_addWindowFor(ref, window)) {
// find the correct InfoView sub-class
BMediaRoster *roster = BMediaRoster::CurrentRoster();
dormant_node_info dormantNodeInfo;
if (ref->kind() & B_FILE_INTERFACE)
{
window->AddChild(new FileNodeInfoView(ref));
}
else if (roster->GetDormantNodeFor(ref->node(), &dormantNodeInfo) != B_OK) {
port_info portInfo;
app_info appInfo;
if ((get_port_info(ref->node().port, &portInfo) == B_OK)
&& (be_roster->GetRunningAppInfo(portInfo.team, &appInfo) == B_OK)) {
app_info thisAppInfo;
if ((be_app->GetAppInfo(&thisAppInfo) != B_OK)
|| ((strcmp(appInfo.signature, thisAppInfo.signature) != 0)
&& (strcmp(appInfo.signature, addon_host::g_appSignature) != 0))) {
window->AddChild(new AppNodeInfoView(ref));
}
else {
window->AddChild(new LiveNodeInfoView(ref));
}
}
else {
window->AddChild(new LiveNodeInfoView(ref));
}
}
else {
window->AddChild(new LiveNodeInfoView(ref));
}
// display the window
window->Show();
return B_OK;
}
// failed
delete window;
return B_ERROR;
}
status_t InfoWindowManager::openWindowFor(
const dormant_node_info &info) {
D_WINDOW(("InfoWindowManager::openWindowFor(dormant_node)\n"));
// make absolutely sure we're locked
if (!IsLocked()) {
debugger("The looper must be locked !");
}
BWindow *window = 0;
if (_findWindowFor(info, &window)) {
// window for this node already exists, activate it
window->SetWorkspaces(B_CURRENT_WORKSPACE);
window->Activate();
return B_OK;
}
BRect frame = InfoView::M_DEFAULT_FRAME;
frame.OffsetTo(m_nextWindowPosition);
m_nextWindowPosition += M_DEFAULT_OFFSET;
window = new InfoWindow(frame);
if (_addWindowFor(info, window)) {
window->AddChild(new DormantNodeInfoView(info));
window->Show();
return B_OK;
}
// failed
delete window;
return B_ERROR;
}
status_t InfoWindowManager::openWindowFor(
const Connection &connection) {
D_WINDOW(("InfoWindowManager::openWindowFor(connection)\n"));
// make absolutely sure we're locked
if (!IsLocked()) {
debugger("The looper must be locked !");
}
BWindow *window = 0;
if (_findWindowFor(connection.source(), connection.destination(), &window)) {
// window for this node already exists, activate it
window->SetWorkspaces(B_CURRENT_WORKSPACE);
window->Activate();
return B_OK;
}
BRect frame = InfoView::M_DEFAULT_FRAME;
frame.OffsetTo(m_nextWindowPosition);
m_nextWindowPosition += M_DEFAULT_OFFSET;
window = new InfoWindow(frame);
if (_addWindowFor(connection, window)) {
window->AddChild(new ConnectionInfoView(connection));
window->Show();
return B_OK;
}
// failed
delete window;
return B_ERROR;
}
status_t InfoWindowManager::openWindowFor(
const media_input &input) {
D_WINDOW(("InfoWindowManager::openWindowFor(input)\n"));
// make absolutely sure we're locked
if (!IsLocked()) {
debugger("The looper must be locked !");
}
BWindow *window = 0;
if (_findWindowFor(input.destination, &window)) {
// window for this node already exists, activate it
window->SetWorkspaces(B_CURRENT_WORKSPACE);
window->Activate();
return B_OK;
}
BRect frame = InfoView::M_DEFAULT_FRAME;
frame.OffsetTo(m_nextWindowPosition);
m_nextWindowPosition += M_DEFAULT_OFFSET;
window = new InfoWindow(frame);
if (_addWindowFor(input, window)) {
window->AddChild(new EndPointInfoView(input));
window->Show();
return B_OK;
}
// failed
delete window;
return B_ERROR;
}
status_t InfoWindowManager::openWindowFor(
const media_output &output) {
D_WINDOW(("InfoWindowManager::openWindowFor(output)\n"));
// make absolutely sure we're locked
if (!IsLocked()) {
debugger("The looper must be locked !");
}
BWindow *window = 0;
if (_findWindowFor(output.source, &window)) {
// window for this node already exists, activate it
window->SetWorkspaces(B_CURRENT_WORKSPACE);
window->Activate();
return B_OK;
}
BRect frame = InfoView::M_DEFAULT_FRAME;
frame.OffsetTo(m_nextWindowPosition);
m_nextWindowPosition += M_DEFAULT_OFFSET;
window = new BWindow(frame, "", B_DOCUMENT_WINDOW, 0);
if (_addWindowFor(output, window)) {
window->AddChild(new EndPointInfoView(output));
window->Show();
return B_OK;
}
// failed
delete window;
return B_ERROR;
}
// -------------------------------------------------------- //
// *** BLooper impl
// -------------------------------------------------------- //
void InfoWindowManager::MessageReceived(
BMessage *message) {
D_MESSAGE(("InfoWindowManager::MessageReceived()\n"));
switch (message->what) {
case M_LIVE_NODE_WINDOW_CLOSED: {
D_MESSAGE((" -> M_LIVE_NODE_WINDOW_CLOSED\n"));
int32 nodeID;
if (message->FindInt32("nodeID", &nodeID) != B_OK) {
return;
}
_removeWindowFor(nodeID);
break;
}
case M_DORMANT_NODE_WINDOW_CLOSED: {
D_MESSAGE((" -> M_DORMANT_NODE_WINDOW_CLOSED\n"));
dormant_node_info info;
if (message->FindInt32("addOnID", &info.addon) != B_OK) {
return;
}
if (message->FindInt32("flavorID", &info.flavor_id) != B_OK) {
return;
}
_removeWindowFor(info);
break;
}
case M_CONNECTION_WINDOW_CLOSED: {
D_MESSAGE((" -> M_CONNECTION_WINDOW_CLOSED\n"));
media_source source;
if (message->FindInt32("source_port", &source.port) != B_OK) {
return;
}
if (message->FindInt32("source_id", &source.id) != B_OK) {
return;
}
media_destination destination;
if (message->FindInt32("destination_port", &destination.port) != B_OK) {
return;
}
if (message->FindInt32("destination_id", &destination.id) != B_OK) {
return;
}
_removeWindowFor(source, destination);
break;
}
case M_INPUT_WINDOW_CLOSED: {
D_MESSAGE((" -> M_INPUT_WINDOW_CLOSED\n"));
media_destination destination;
if (message->FindInt32("destination_port", &destination.port) != B_OK) {
return;
}
if (message->FindInt32("destination_id", &destination.id) != B_OK) {
return;
}
_removeWindowFor(destination);
break;
}
case M_OUTPUT_WINDOW_CLOSED: {
D_MESSAGE((" -> M_OUTPUT_WINDOW_CLOSED\n"));
media_source source;
if (message->FindInt32("source_port", &source.port) != B_OK) {
return;
}
if (message->FindInt32("source_id", &source.id) != B_OK) {
return;
}
_removeWindowFor(source);
break;
}
case NodeRef::M_RELEASED: {
D_MESSAGE((" -> NodeRef::M_RELEASED\n"));
int32 nodeID;
if (message->FindInt32("nodeID", &nodeID) != B_OK) {
return;
}
BWindow *window;
if (_findWindowFor(nodeID, &window)) {
window->Lock();
window->Quit();
_removeWindowFor(nodeID);
}
break;
}
case B_MEDIA_CONNECTION_BROKEN: {
D_MESSAGE((" -> B_MEDIA_CONNECTION_BROKEN\n"));
const void *data;
ssize_t dataSize;
if (message->FindData("source", B_RAW_TYPE, &data, &dataSize) != B_OK) {
return;
}
const media_source source = *reinterpret_cast<const media_source *>(data);
if (message->FindData("destination", B_RAW_TYPE, &data, &dataSize) != B_OK) {
return;
}
const media_destination destination = *reinterpret_cast<const media_destination *>(data);
BWindow *window;
if (_findWindowFor(source, destination, &window)) {
window->Lock();
window->Quit();
_removeWindowFor(source, destination);
}
break;
}
default: {
BLooper::MessageReceived(message);
}
}
}
// -------------------------------------------------------- //
// *** internal operations
// -------------------------------------------------------- //
bool InfoWindowManager::_addWindowFor(
const NodeRef *ref,
BWindow *window) {
D_INTERNAL(("InfoWindowManager::_addWindowFor(live_node)\n"));
if (!m_liveNodeWindows) {
m_liveNodeWindows = new BList();
}
live_node_window *entry = new live_node_window(ref, window);
if (m_liveNodeWindows->AddItem(reinterpret_cast<void *>(entry))) {
add_observer(this, entry->ref);
return true;
}
return false;
}
bool InfoWindowManager::_findWindowFor(
int32 nodeID,
BWindow **outWindow) {
D_INTERNAL(("InfoWindowManager::_findWindowFor(live_node)\n"));
if (!m_liveNodeWindows) {
return false;
}
for (int32 i = 0; i < m_liveNodeWindows->CountItems(); i++) {
live_node_window *entry = static_cast<live_node_window *>
(m_liveNodeWindows->ItemAt(i));
if (entry->ref->id() == nodeID) {
*outWindow = entry->window;
return true;
}
}
return false;
}
void InfoWindowManager::_removeWindowFor(
int32 nodeID) {
D_INTERNAL(("InfoWindowManager::_removeWindowFor(live_node)\n"));
if (!m_liveNodeWindows) {
return;
}
for (int32 i = 0; i < m_liveNodeWindows->CountItems(); i++) {
live_node_window *entry = static_cast<live_node_window *>
(m_liveNodeWindows->ItemAt(i));
if (entry->ref->id() == nodeID) {
m_liveNodeWindows->RemoveItem(reinterpret_cast<void *>(entry));
remove_observer(this, entry->ref);
delete entry;
}
}
if (m_liveNodeWindows->CountItems() <= 0) {
delete m_liveNodeWindows;
m_liveNodeWindows = 0;
}
}
bool InfoWindowManager::_addWindowFor(
const dormant_node_info &info,
BWindow *window) {
D_INTERNAL(("InfoWindowManager::_addWindowFor(dormant_node)\n"));
if (!m_dormantNodeWindows) {
m_dormantNodeWindows = new BList();
}
dormant_node_window *entry = new dormant_node_window(info, window);
return m_dormantNodeWindows->AddItem(reinterpret_cast<void *>(entry));
}
bool InfoWindowManager::_findWindowFor(
const dormant_node_info &info,
BWindow **outWindow) {
D_INTERNAL(("InfoWindowManager::_findWindowFor(dormant_node)\n"));
if (!m_dormantNodeWindows) {
return false;
}
for (int32 i = 0; i < m_dormantNodeWindows->CountItems(); i++) {
dormant_node_window *entry = static_cast<dormant_node_window *>
(m_dormantNodeWindows->ItemAt(i));
if ((entry->info.addon == info.addon)
&& (entry->info.flavor_id == info.flavor_id)) {
*outWindow = entry->window;
return true;
}
}
return false;
}
void InfoWindowManager::_removeWindowFor(
const dormant_node_info &info) {
D_INTERNAL(("InfoWindowManager::_removeWindowFor(dormant_node)\n"));
if (!m_dormantNodeWindows) {
return;
}
for (int32 i = 0; i < m_dormantNodeWindows->CountItems(); i++) {
dormant_node_window *entry = static_cast<dormant_node_window *>
(m_dormantNodeWindows->ItemAt(i));
if ((entry->info.addon == info.addon)
&& (entry->info.flavor_id == info.flavor_id)) {
m_dormantNodeWindows->RemoveItem(reinterpret_cast<void *>(entry));
delete entry;
}
}
if (m_dormantNodeWindows->CountItems() >= 0) {
delete m_dormantNodeWindows;
m_dormantNodeWindows = 0;
}
}
bool InfoWindowManager::_addWindowFor(
const Connection &connection,
BWindow *window) {
D_INTERNAL(("InfoWindowManager::_addWindowFor(connection)\n"));
if (!m_connectionWindows) {
m_connectionWindows = new BList();
}
connection_window *entry = new connection_window(connection.source(),
connection.destination(),
window);
return m_connectionWindows->AddItem(reinterpret_cast<void *>(entry));
}
bool InfoWindowManager::_findWindowFor(
const media_source &source,
const media_destination &destination,
BWindow **outWindow) {
D_INTERNAL(("InfoWindowManager::_findWindowFor(connection)\n"));
if (!m_connectionWindows) {
return false;
}
for (int32 i = 0; i < m_connectionWindows->CountItems(); i++) {
connection_window *entry = static_cast<connection_window *>
(m_connectionWindows->ItemAt(i));
if ((entry->source == source)
&& (entry->destination == destination)) {
*outWindow = entry->window;
return true;
}
}
return false;
}
void InfoWindowManager::_removeWindowFor(
const media_source &source,
const media_destination &destination) {
D_INTERNAL(("InfoWindowManager::_removeWindowFor(connection)\n"));
if (!m_connectionWindows) {
return;
}
for (int32 i = 0; i < m_connectionWindows->CountItems(); i++) {
connection_window *entry = static_cast<connection_window *>
(m_connectionWindows->ItemAt(i));
if ((entry->source == source)
&& (entry->destination == destination)) {
m_connectionWindows->RemoveItem(reinterpret_cast<void *>(entry));
delete entry;
}
}
if (m_connectionWindows->CountItems() >= 0) {
delete m_connectionWindows;
m_connectionWindows = 0;
}
}
bool InfoWindowManager::_addWindowFor(
const media_input &input,
BWindow *window) {
D_INTERNAL(("InfoWindowManager::_addWindowFor(input)\n"));
if (!m_inputWindows) {
m_inputWindows = new BList();
}
input_window *entry = new input_window(input.destination, window);
return m_inputWindows->AddItem(reinterpret_cast<void *>(entry));
}
bool InfoWindowManager::_findWindowFor(
const media_destination &destination,
BWindow **outWindow) {
D_INTERNAL(("InfoWindowManager::_findWindowFor(input)\n"));
if (!m_inputWindows) {
return false;
}
for (int32 i = 0; i < m_inputWindows->CountItems(); i++) {
input_window *entry = static_cast<input_window *>
(m_inputWindows->ItemAt(i));
if (entry->destination == destination) {
*outWindow = entry->window;
return true;
}
}
return false;
}
void InfoWindowManager::_removeWindowFor(
const media_destination &destination) {
D_INTERNAL(("InfoWindowManager::_removeWindowFor(input)\n"));
if (!m_inputWindows) {
return;
}
for (int32 i = 0; i < m_inputWindows->CountItems(); i++) {
input_window *entry = static_cast<input_window *>
(m_inputWindows->ItemAt(i));
if (entry->destination == destination) {
m_inputWindows->RemoveItem(reinterpret_cast<void *>(entry));
delete entry;
}
}
if (m_inputWindows->CountItems() >= 0) {
delete m_inputWindows;
m_inputWindows = 0;
}
}
bool InfoWindowManager::_addWindowFor(
const media_output &output,
BWindow *window) {
D_INTERNAL(("InfoWindowManager::_addWindowFor(output)\n"));
if (!m_outputWindows) {
m_outputWindows = new BList();
}
output_window *entry = new output_window(output.source, window);
return m_outputWindows->AddItem(reinterpret_cast<void *>(entry));
}
bool InfoWindowManager::_findWindowFor(
const media_source &source,
BWindow **outWindow) {
D_INTERNAL(("InfoWindowManager::_findWindowFor(output)\n"));
if (!m_outputWindows) {
return false;
}
for (int32 i = 0; i < m_outputWindows->CountItems(); i++) {
output_window *entry = static_cast<output_window *>
(m_outputWindows->ItemAt(i));
if (entry->source == source) {
*outWindow = entry->window;
return true;
}
}
return false;
}
void InfoWindowManager::_removeWindowFor(
const media_source &source) {
D_INTERNAL(("InfoWindowManager::_removeWindowFor(output)\n"));
if (!m_outputWindows) {
return;
}
for (int32 i = 0; i < m_outputWindows->CountItems(); i++) {
output_window *entry = static_cast<output_window *>
(m_outputWindows->ItemAt(i));
if (entry->source == source) {
m_outputWindows->RemoveItem(reinterpret_cast<void *>(entry));
delete entry;
}
}
if (m_outputWindows->CountItems() >= 0) {
delete m_outputWindows;
m_outputWindows = 0;
}
}
// END -- InfoWindowManager.cpp --

View File

@ -0,0 +1,180 @@
// InfoWindowManager.h
//
// * PURPOSE
// Manages all the ParameterWindows and control panels.
// Will not let you open multiple windows referring to
// the same node, and takes care of quitting them all
// when shut down.
//
// * HISTORY
// c.lenz 17feb2000 Begun
//
#ifndef __InfoWindowManager_H__
#define __InfoWindowManager_H__
// Application Kit
#include <Looper.h>
// Interface Kit
#include <Point.h>
class BList;
class BWindow;
#include "cortex_defs.h"
__BEGIN_CORTEX_NAMESPACE
class Connection;
class NodeRef;
class InfoWindowManager :
public BLooper {
public: // *** constants
// the screen position where the first window should
// be displayed
static const BPoint M_INIT_POSITION;
// horizontal/vertical offset by which subsequent
// windows positions are shifted
static const BPoint M_DEFAULT_OFFSET;
enum message_t {
M_INFO_WINDOW_REQUESTED = InfoView_message_base,
M_LIVE_NODE_WINDOW_CLOSED,
M_DORMANT_NODE_WINDOW_CLOSED,
M_CONNECTION_WINDOW_CLOSED,
M_INPUT_WINDOW_CLOSED,
M_OUTPUT_WINDOW_CLOSED
};
private: // *** ctor/dtor
// hidden ctor; is called only from inside Instance()
InfoWindowManager();
public:
// quits all registered info windows
virtual ~InfoWindowManager();
public: // *** singleton access
// access to the one and only instance of this class
static InfoWindowManager *Instance();
// will delete the singleton instance and take down all
// open windows
static void shutDown();
public: // *** operations
status_t openWindowFor(
const NodeRef *ref);
status_t openWindowFor(
const dormant_node_info &info);
status_t openWindowFor(
const Connection &connection);
status_t openWindowFor(
const media_input &input);
status_t openWindowFor(
const media_output &output);
public: // *** BLooper impl
virtual void MessageReceived(
BMessage *message);
private: // *** internal operations
// management of windows for live nodes
bool _addWindowFor(
const NodeRef *ref,
BWindow *window);
bool _findWindowFor(
int32 nodeID,
BWindow **outWindow);
void _removeWindowFor(
int32 nodeID);
// management of windows for dormant nodes
bool _addWindowFor(
const dormant_node_info &info,
BWindow *window);
bool _findWindowFor(
const dormant_node_info &info,
BWindow **outWindow);
void _removeWindowFor(
const dormant_node_info &info);
// management of windows for connections
bool _addWindowFor(
const Connection &connection,
BWindow *window);
bool _findWindowFor(
const media_source &source,
const media_destination &destination,
BWindow **outWindow);
void _removeWindowFor(
const media_source &source,
const media_destination &destination);
// management of windows for media_inputs
bool _addWindowFor(
const media_input &input,
BWindow *window);
bool _findWindowFor(
const media_destination &destination,
BWindow **outWindow);
void _removeWindowFor(
const media_destination &destination);
// management of windows for media_outputs
bool _addWindowFor(
const media_output &output,
BWindow *window);
bool _findWindowFor(
const media_source &source,
BWindow **outWindow);
void _removeWindowFor(
const media_source &source);
private: // *** data members
// list of all currently open windows about live nodes
BList *m_liveNodeWindows;
// list of all currently open windows about dormant nodes
BList *m_dormantNodeWindows;
// list of all currently open windows about connections
BList *m_connectionWindows;
// list of all currently open windows about media_inputs
BList *m_inputWindows;
// list of all currently open windows about media_outputs
BList *m_outputWindows;
// the BPoint at which the last InfoWindow was initially
// opened
BPoint m_nextWindowPosition;
private: // *** static members
// the magic singleton instance
static InfoWindowManager *s_instance;
};
__END_CORTEX_NAMESPACE
#endif /*__InfoWindowManager_H__*/

View File

@ -0,0 +1,110 @@
// LiveNodeInfoView.cpp
#include "LiveNodeInfoView.h"
// InfoView
#include "InfoWindowManager.h"
// NodeManager
#include "NodeGroup.h"
#include "NodeRef.h"
// Support
#include "MediaIcon.h"
#include "MediaString.h"
// Media Kit
#include <MediaNode.h>
// Interface Kit
#include <Window.h>
__USE_CORTEX_NAMESPACE
#include <Debug.h>
#define D_METHOD(x) //PRINT (x)
#define D_MESSAGE(x) //PRINT (x)
// -------------------------------------------------------- //
// *** ctor/dtor (public)
// -------------------------------------------------------- //
LiveNodeInfoView::LiveNodeInfoView(
const NodeRef *ref)
: InfoView(ref->name(), "Live Media Node",
new MediaIcon(ref->nodeInfo(), B_LARGE_ICON)),
m_nodeID(ref->id())
{
D_METHOD(("LiveNodeInfoView::LiveNodeInfoView()\n"));
// adjust view properties
setSideBarWidth(be_plain_font->StringWidth(" Run Mode ") + 2 * InfoView::M_H_MARGIN);
// add "Node ID" field
BString s;
s << ref->id();
addField("Node ID", s);
// add "Port" field
s = "";
s << ref->node().port;
port_info portInfo;
if (get_port_info(ref->node().port, &portInfo) == B_OK)
{
s << " (" << portInfo.name << ")";
}
addField("Port", s);
// add separator field
addField("", "");
// add "Kinds" field
addField("Kinds", MediaString::getStringFor(static_cast<node_kind>(ref->kind())));
// add "Run Mode" field
BMediaNode::run_mode runMode = static_cast<BMediaNode::run_mode>(ref->runMode());
if (runMode < 1)
{
NodeGroup *group = ref->group();
if (group)
{
runMode = group->runMode();
}
}
addField("Run Mode", MediaString::getStringFor(runMode));
// add "Latency" field
bigtime_t latency;
if (ref->totalLatency(&latency) == B_OK)
{
s = "";
if (latency > 0)
{
s << static_cast<float>(latency) / 1000.0f << " ms";
}
else
{
s = "?";
}
addField("Latency", s);
}
}
LiveNodeInfoView::~LiveNodeInfoView() {
D_METHOD(("LiveNodeInfoView::~LiveNodeInfoView()\n"));
}
// -------------------------------------------------------- //
// *** BView implementation (public)
// -------------------------------------------------------- //
void LiveNodeInfoView::DetachedFromWindow() {
D_METHOD(("LiveNodeInfoView::DetachedFromWindow()\n"));
InfoWindowManager *manager = InfoWindowManager::Instance();
if (manager) {
BMessage message(InfoWindowManager::M_LIVE_NODE_WINDOW_CLOSED);
message.AddInt32("nodeID", m_nodeID);
manager->PostMessage(&message);
}
}
// END -- LiveNodeInfoView.cpp --

View File

@ -0,0 +1,45 @@
// LiveNodeInfoView.h (Cortex/InfoView)
//
// * PURPOSE
// Defines fields to be displayed for all live MediaNodes,
// which can be added to for special nodes like file-readers
// (see FileNodeInfoView) etc.
//
// * HISTORY
// c.lenz 5nov99 Begun
//
#ifndef __LiveNodeInfoView_H__
#define __LiveNodeInfoView_H__
#include "InfoView.h"
#include "cortex_defs.h"
__BEGIN_CORTEX_NAMESPACE
class NodeRef;
class LiveNodeInfoView :
public InfoView {
public: // *** ctor/dtor
// adds the live-node relevant fields the the
// InfoView
LiveNodeInfoView(
const NodeRef *ref);
virtual ~LiveNodeInfoView();
public: // *** BView impl
// notify InfoWindowManager
virtual void DetachedFromWindow();
private: // *** data members
int32 m_nodeID;
};
__END_CORTEX_NAMESPACE
#endif /* __LiveNodeInfoView_H__ */

View File

@ -0,0 +1,27 @@
Copyright (c) 1999-2000, Eric Moon.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions, and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions, and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@ -0,0 +1,773 @@
// MediaJack.cpp
// c.lenz 10oct99
#include "MediaJack.h"
// MediaRoutingView
#include "MediaRoutingDefs.h"
#include "MediaRoutingView.h"
#include "MediaWire.h"
// InfoWindow
#include "InfoWindowManager.h"
// Support
#include "cortex_ui.h"
#include "MediaString.h"
// TipManager
#include "TipManager.h"
// Application Kit
#include <Application.h>
// Interface Kit
#include <Bitmap.h>
#include <MenuItem.h>
#include <PopUpMenu.h>
__USE_CORTEX_NAMESPACE
#include <Debug.h>
#define D_METHOD(x) //PRINT (x)
#define D_DRAW(x) //PRINT (x)
#define D_MOUSE(x) //PRINT (x)
// -------------------------------------------------------- //
// constants
// -------------------------------------------------------- //
float MediaJack::M_DEFAULT_WIDTH = 5.0;
float MediaJack::M_DEFAULT_HEIGHT = 10.0;
const float MediaJack::M_DEFAULT_GAP = 5.0;
const int32 MediaJack::M_MAX_ABBR_LENGTH = 3;
// -------------------------------------------------------- //
// *** ctor/dtor
// -------------------------------------------------------- //
MediaJack::MediaJack(
media_input input)
: DiagramEndPoint(BRect(0.0, 0.0, M_DEFAULT_WIDTH, M_DEFAULT_HEIGHT)),
m_jackType(M_INPUT),
m_bitmap(0),
m_index(input.destination.id),
m_node(input.node),
m_source(input.source),
m_destination(input.destination),
m_format(input.format),
m_label(input.name),
m_abbreviation("")
{
D_METHOD(("MediaJack::MediaJack()\n"));
makeSelectable(false);
if (m_label == "")
m_label = "Input";
_updateAbbreviation();
}
MediaJack::MediaJack(
media_output output)
: DiagramEndPoint(BRect(0.0, 0.0, M_DEFAULT_WIDTH, M_DEFAULT_HEIGHT)),
m_jackType(M_OUTPUT),
m_bitmap(0),
m_index(output.source.id),
m_node(output.node),
m_source(output.source),
m_destination(output.destination),
m_format(output.format),
m_label(output.name),
m_abbreviation("")
{
D_METHOD(("MediaJack::MediaJack()\n"));
makeSelectable(false);
if (m_label == "")
m_label = "Output";
_updateAbbreviation();
}
MediaJack::~MediaJack()
{
D_METHOD(("MediaJack::~MediaJack()\n"));
delete m_bitmap;
}
// -------------------------------------------------------- //
// *** accessors
// -------------------------------------------------------- //
status_t MediaJack::getInput(
media_input *input) const
{
D_METHOD(("MediaJack::getInput()\n"));
if (isInput())
{
input->node = m_node;
input->source = m_source;
input->destination = m_destination;
input->format = m_format;
m_label.CopyInto(input->name, 0, 64);
return B_OK;
}
return B_ERROR;
}
status_t MediaJack::getOutput(
media_output *output) const
{
D_METHOD(("MediaJack::getOutput()\n"));
if (isOutput())
{
output->node = m_node;
output->source = m_source;
output->destination = m_destination;
output->format = m_format;
m_label.CopyInto(output->name, 0, 64);
return B_OK;
}
return B_ERROR;
}
// -------------------------------------------------------- //
// *** derived from DiagramEndPoint (public)
// -------------------------------------------------------- //
void MediaJack::attachedToDiagram()
{
D_METHOD(("MediaJack::attachedToDiagram()\n"));
_updateBitmap();
}
void MediaJack::detachedFromDiagram()
{
D_METHOD(("MediaJack::detachedFromDiagram()\n"));
// make sure we're no longer displaying a tooltip
TipManager *tips = TipManager::Instance();
tips->hideTip(view()->ConvertToScreen(frame()));
}
void MediaJack::drawEndPoint()
{
D_DRAW(("MediaJack::drawEndPoint()\n"));
if (m_bitmap)
{
view()->DrawBitmap(m_bitmap, frame().LeftTop());
}
}
BPoint MediaJack::connectionPoint() const
{
D_METHOD(("MediaJack::connectionPoint()\n"));
switch (dynamic_cast<MediaRoutingView *>(view())->getLayout())
{
case MediaRoutingView::M_ICON_VIEW:
{
if (isInput())
{
return BPoint(frame().left - 1.0, frame().top + frame().Height() / 2.0);
}
else if (isOutput())
{
return BPoint(frame().right + 1.0, frame().top + frame().Height() / 2.0);
}
break;
}
case MediaRoutingView::M_MINI_ICON_VIEW:
{
if (isInput())
{
return BPoint(frame().left + frame().Width() / 2.0, frame().top - 1.0);
}
else if (isOutput())
{
return BPoint(frame().left + frame().Width() / 2.0, frame().bottom + 1.0);
}
break;
}
}
return BPoint(-1.0, -1.0);
}
bool MediaJack::connectionRequested(
DiagramEndPoint *which)
{
D_METHOD(("MediaJack::connectionRequested()\n"));
MediaJack *otherJack = dynamic_cast<MediaJack *>(which);
if (otherJack && (otherJack->m_jackType != m_jackType) && !isConnected())
{
return true;
}
return false;
}
void MediaJack::mouseDown(
BPoint point,
uint32 buttons,
uint32 clicks)
{
D_MOUSE(("MediaJack::mouseOver()\n"));
// if connected, redirect to the wire
if (isConnected())
{
dynamic_cast<MediaWire *>(wire())->mouseDown(point, buttons, clicks);
return;
}
// else we handle the mouse event ourselves
switch (buttons)
{
case B_SECONDARY_MOUSE_BUTTON:
{
showContextMenu(point);
break;
}
default:
{
DiagramEndPoint::mouseDown(point, buttons, clicks);
}
}
}
void MediaJack::mouseOver(
BPoint point,
uint32 transit)
{
D_MOUSE(("MediaJack::mouseOver()\n"));
switch (transit)
{
case B_ENTERED_VIEW:
{
be_app->SetCursor(M_CABLE_CURSOR);
TipManager *tips = TipManager::Instance();
BString tipText = m_label.String();
tipText << " (" << MediaString::getStringFor(m_format.type) << ")";
tips->showTip(tipText.String(),view()->ConvertToScreen(frame()),
TipManager::LEFT_OFFSET_FROM_POINTER, BPoint(12.0, 8.0));
break;
}
case B_EXITED_VIEW:
{
if (!view()->isWireTracking())
{
be_app->SetCursor(B_HAND_CURSOR);
}
break;
}
}
}
void MediaJack::messageDragged(
BPoint point,
uint32 transit,
const BMessage *message)
{
D_MOUSE(("MediaJack::messageDragged()\n"));
switch (transit)
{
case B_ENTERED_VIEW:
{
be_app->SetCursor(M_CABLE_CURSOR);
break;
}
case B_EXITED_VIEW:
{
if (!view()->isWireTracking())
{
be_app->SetCursor(B_HAND_CURSOR);
}
break;
}
}
DiagramEndPoint::messageDragged(point, transit, message);
}
void MediaJack::selected()
{
D_METHOD(("MediaJack::selected()\n"));
_updateBitmap();
view()->Invalidate(frame());
}
void MediaJack::deselected()
{
D_METHOD(("MediaJack::deselected()\n"));
_updateBitmap();
view()->Invalidate(frame());
}
void MediaJack::connected()
{
D_METHOD(("MediaJack::connected()\n"));
_updateBitmap();
view()->Invalidate(frame());
}
void MediaJack::disconnected()
{
D_METHOD(("MediaJack::disconnected()\n"));
_updateBitmap();
view()->Invalidate(frame());
}
// -------------------------------------------------------- //
// *** operations (public)
// -------------------------------------------------------- //
void MediaJack::layoutChanged(
int32 layout)
{
D_METHOD(("MediaJack::layoutChanged\n"));
resizeTo(M_DEFAULT_WIDTH, M_DEFAULT_HEIGHT);
_updateBitmap();
}
void MediaJack::setPosition(
float offset,
float leftTopBoundary,
float rightBottomBoundary,
BRegion *updateRegion)
{
D_METHOD(("MediaJack::setPosition\n"));
switch (dynamic_cast<MediaRoutingView *>(view())->getLayout())
{
case MediaRoutingView::M_ICON_VIEW:
{
if (isInput())
{
moveTo(BPoint(leftTopBoundary, offset), updateRegion);
}
else if (isOutput())
{
moveTo(BPoint(rightBottomBoundary - frame().Width(), offset), updateRegion);
}
break;
}
case MediaRoutingView::M_MINI_ICON_VIEW:
{
if (isInput())
{
moveTo(BPoint(offset, leftTopBoundary), updateRegion);
}
else if (isOutput())
{
moveTo(BPoint(offset, rightBottomBoundary - frame().Height()), updateRegion);
}
break;
}
}
}
// -------------------------------------------------------- //
// *** internal methods (private)
// -------------------------------------------------------- //
void MediaJack::_updateBitmap()
{
D_METHOD(("MediaJack::_updateBitmap()\n"));
if (m_bitmap)
{
delete m_bitmap;
}
BBitmap *tempBitmap = new BBitmap(frame().OffsetToCopy(0.0, 0.0), B_CMAP8, true);
tempBitmap->Lock();
{
BView *tempView = new BView(tempBitmap->Bounds(), "", B_FOLLOW_NONE, 0);
tempBitmap->AddChild(tempView);
tempView->SetOrigin(0.0, 0.0);
int32 layout = dynamic_cast<MediaRoutingView *>(view())->getLayout();
_drawInto(tempView, tempView->Bounds(), layout);
tempView->Sync();
tempBitmap->RemoveChild(tempView);
delete tempView;
}
tempBitmap->Unlock();
m_bitmap = new BBitmap(tempBitmap);
delete tempBitmap;
}
void MediaJack::_drawInto(
BView *target,
BRect targetRect,
int32 layout)
{
D_METHOD(("MediaJack::_drawInto()\n"));
bool selected = isConnecting() || isSelected();
switch (layout)
{
case MediaRoutingView::M_ICON_VIEW:
{
if (isInput())
{
BRect r;
BPoint p;
// fill rect
r = targetRect;
target->SetLowColor(M_GRAY_COLOR);
r.left += 2.0;
target->FillRect(r, B_SOLID_LOW);
// draw connection point
r = targetRect;
p.Set(0.0, frame().Height() / 2.0 - 2.0);
target->BeginLineArray(4);
{
target->AddLine(r.LeftTop(),
p,
M_DARK_GRAY_COLOR);
target->AddLine(r.LeftTop() + BPoint(1.0, 0.0),
p + BPoint(1.0, 0.0),
M_LIGHT_GRAY_COLOR);
target->AddLine(p + BPoint(0.0, 5.0),
r.LeftBottom(),
M_DARK_GRAY_COLOR);
target->AddLine(p + BPoint(1.0, 5.0),
r.LeftBottom() + BPoint(1.0, 0.0),
M_LIGHT_GRAY_COLOR);
}
target->EndLineArray();
if (isConnected() || isConnecting())
{
target->BeginLineArray(11);
{
target->AddLine(p, p, M_DARK_GRAY_COLOR);
target->AddLine(p + BPoint(0.0, 4.0), p + BPoint(0.0, 4.0), M_DARK_GRAY_COLOR);
target->AddLine(p + BPoint(1.0, 0.0), p + BPoint(4.0, 0.0), M_DARK_GRAY_COLOR);
target->AddLine(p + BPoint(1.0, 4.0), p + BPoint(4.0, 4.0), M_LIGHT_GRAY_COLOR);
target->AddLine(p + BPoint(4.0, 1.0), p + BPoint(4.0, 3.0), M_LIGHT_GRAY_COLOR);
target->AddLine(p + BPoint(0.0, 1.0), p + BPoint(2.0, 1.0), selected ? M_BLUE_COLOR : M_DARK_GRAY_COLOR);
target->AddLine(p + BPoint(3.0, 1.0), p + BPoint(3.0, 1.0), M_MED_GRAY_COLOR);
target->AddLine(p + BPoint(0.0, 2.0), p + BPoint(2.0, 2.0), selected ? M_LIGHT_BLUE_COLOR : M_LIGHT_GRAY_COLOR);
target->AddLine(p + BPoint(3.0, 2.0), p + BPoint(3.0, 2.0), selected ? M_BLUE_COLOR : M_DARK_GRAY_COLOR);
target->AddLine(p + BPoint(0.0, 3.0), p + BPoint(2.0, 3.0), selected ? M_BLUE_COLOR : M_DARK_GRAY_COLOR);
target->AddLine(p + BPoint(3.0, 3.0), p + BPoint(3.0, 3.0), M_MED_GRAY_COLOR);
}
target->EndLineArray();
}
else
{
target->BeginLineArray(7);
{
target->AddLine(p, p + BPoint(0.0, 4.0), M_DARK_GRAY_COLOR);
target->AddLine(p + BPoint(1.0, 0.0), p + BPoint(4.0, 0.0), M_DARK_GRAY_COLOR);
target->AddLine(p + BPoint(1.0, 4.0), p + BPoint(4.0, 4.0), M_LIGHT_GRAY_COLOR);
target->AddLine(p + BPoint(4.0, 1.0), p + BPoint(4.0, 3.0), M_LIGHT_GRAY_COLOR);
target->AddLine(p + BPoint(1.0, 1.0), p + BPoint(3.0, 1.0), M_MED_GRAY_COLOR);
target->AddLine(p + BPoint(1.0, 2.0), p + BPoint(3.0, 2.0), M_MED_GRAY_COLOR);
target->AddLine(p + BPoint(1.0, 3.0), p + BPoint(3.0, 3.0), M_MED_GRAY_COLOR);
}
target->EndLineArray();
}
// draw abbreviation string
BFont font(be_plain_font);
font_height fh;
font.SetSize(font.Size() - 2.0);
font.GetHeight(&fh);
p.x += 7.0;
p.y = (frame().Height() / 2.0) + (fh.ascent / 2.0);
target->SetFont(&font);
target->SetDrawingMode(B_OP_OVER);
target->SetHighColor((isConnected() || isConnecting()) ?
M_MED_GRAY_COLOR :
M_DARK_GRAY_COLOR);
target->DrawString(m_abbreviation.String(), p);
}
else if (isOutput())
{
BRect r;
BPoint p;
// fill rect
r = targetRect;
target->SetLowColor(M_GRAY_COLOR);
r.right -= 2.0;
target->FillRect(r, B_SOLID_LOW);
// draw connection point
r = targetRect;
p.Set(targetRect.right - 4.0, frame().Height() / 2.0 - 2.0);
target->BeginLineArray(4);
{
target->AddLine(r.RightTop(),
p + BPoint(4.0, 0.0),
M_DARK_GRAY_COLOR);
target->AddLine(r.RightTop() + BPoint(-1.0, 0.0),
p + BPoint(3.0, 0.0),
M_MED_GRAY_COLOR);
target->AddLine(p + BPoint(4.0, 5.0),
r.RightBottom(),
M_DARK_GRAY_COLOR);
target->AddLine(p + BPoint(3.0, 5.0),
r.RightBottom() + BPoint(-1.0, 0.0),
M_MED_GRAY_COLOR);
}
target->EndLineArray();
if (isConnected() || isConnecting())
{
target->BeginLineArray(11);
target->AddLine(p + BPoint(4.0, 0.0), p + BPoint(4.0, 0.0), M_DARK_GRAY_COLOR);
target->AddLine(p + BPoint(4.0, 4.0), p + BPoint(4.0, 4.0), M_DARK_GRAY_COLOR);
target->AddLine(p, p + BPoint(3.0, 0.0), M_DARK_GRAY_COLOR);
target->AddLine(p + BPoint(0.0, 1.0), p + BPoint(0.0, 3.0), M_DARK_GRAY_COLOR);
target->AddLine(p + BPoint(0.0, 4.0), p + BPoint(3.0, 4.0), M_LIGHT_GRAY_COLOR);
target->AddLine(p + BPoint(1.0, 1.0), p + BPoint(1.0, 1.0), M_MED_GRAY_COLOR);
target->AddLine(p + BPoint(2.0, 1.0), p + BPoint(4.0, 1.0), selected ? M_BLUE_COLOR : M_DARK_GRAY_COLOR);
target->AddLine(p + BPoint(1.0, 2.0), p + BPoint(1.0, 2.0), selected ? M_BLUE_COLOR : M_DARK_GRAY_COLOR);
target->AddLine(p + BPoint(2.0, 2.0), p + BPoint(4.0, 2.0), selected ? M_LIGHT_BLUE_COLOR : M_LIGHT_GRAY_COLOR);
target->AddLine(p + BPoint(1.0, 3.0), p + BPoint(1.0, 3.0), M_MED_GRAY_COLOR);
target->AddLine(p + BPoint(2.0, 3.0), p + BPoint(4.0, 3.0), selected ? M_BLUE_COLOR : M_DARK_GRAY_COLOR);
target->EndLineArray();
}
else
{
target->BeginLineArray(7);
target->AddLine(p + BPoint(4.0, 0.0), p + BPoint(4.0, 4.0), M_DARK_GRAY_COLOR);
target->AddLine(p, p + BPoint(3.0, 0.0), M_DARK_GRAY_COLOR);
target->AddLine(p + BPoint(0.0, 1.0), p + BPoint(0.0, 3.0), M_DARK_GRAY_COLOR);
target->AddLine(p + BPoint(0.0, 4.0), p + BPoint(3.0, 4.0), M_LIGHT_GRAY_COLOR);
target->AddLine(p + BPoint(1.0, 1.0), p + BPoint(3.0, 1.0), M_MED_GRAY_COLOR);
target->AddLine(p + BPoint(1.0, 2.0), p + BPoint(3.0, 2.0), M_MED_GRAY_COLOR);
target->AddLine(p + BPoint(1.0, 3.0), p + BPoint(3.0, 3.0), M_MED_GRAY_COLOR);
target->EndLineArray();
}
// draw abbreviation string
BFont font(be_plain_font);
font_height fh;
font.SetSize(font.Size() - 2.0);
font.GetHeight(&fh);
p.x -= font.StringWidth(m_abbreviation.String()) + 2.0;
p.y = (frame().Height() / 2.0) + (fh.ascent / 2.0);
target->SetFont(&font);
target->SetDrawingMode(B_OP_OVER);
target->SetHighColor((isConnected() || isConnecting()) ?
M_MED_GRAY_COLOR :
M_DARK_GRAY_COLOR);
target->DrawString(m_abbreviation.String(), p);
}
break;
}
case MediaRoutingView::M_MINI_ICON_VIEW:
{
if (isInput())
{
BRect r;
BPoint p;
// fill rect
r = targetRect;
target->SetLowColor(M_GRAY_COLOR);
r.top += 2.0;
target->FillRect(r, B_SOLID_LOW);
// draw connection point
r = targetRect;
p.Set(frame().Width() / 2.0 - 2.0, 0.0);
target->BeginLineArray(4);
{
target->AddLine(r.LeftTop(),
p,
M_DARK_GRAY_COLOR);
target->AddLine(r.LeftTop() + BPoint(0.0, 1.0),
p + BPoint(0.0, 1.0),
M_LIGHT_GRAY_COLOR);
target->AddLine(p + BPoint(5.0, 0.0),
r.RightTop(),
M_DARK_GRAY_COLOR);
target->AddLine(p + BPoint(5.0, 1.0),
r.RightTop() + BPoint(0.0, 1.0),
M_LIGHT_GRAY_COLOR);
}
target->EndLineArray();
if (isConnected() || isConnecting())
{
target->BeginLineArray(11);
target->AddLine(p, p, M_DARK_GRAY_COLOR);
target->AddLine(p + BPoint(4.0, 0.0), p + BPoint(4.0, 0.0), M_DARK_GRAY_COLOR);
target->AddLine(p + BPoint(0.0, 1.0), p + BPoint(0.0, 4.0), M_DARK_GRAY_COLOR);
target->AddLine(p + BPoint(4.0, 1.0), p + BPoint(4.0, 4.0), M_LIGHT_GRAY_COLOR);
target->AddLine(p + BPoint(1.0, 4.0), p + BPoint(3.0, 4.0), M_LIGHT_GRAY_COLOR);
target->AddLine(p + BPoint(1.0, 0.0), p + BPoint(1.0, 2.0), selected ? M_BLUE_COLOR : M_DARK_GRAY_COLOR);
target->AddLine(p + BPoint(1.0, 3.0), p + BPoint(1.0, 3.0), M_MED_GRAY_COLOR);
target->AddLine(p + BPoint(2.0, 0.0), p + BPoint(2.0, 2.0), selected ? M_LIGHT_BLUE_COLOR : M_LIGHT_GRAY_COLOR);
target->AddLine(p + BPoint(2.0, 3.0), p + BPoint(2.0, 3.0), selected ? M_BLUE_COLOR : M_DARK_GRAY_COLOR);
target->AddLine(p + BPoint(3.0, 0.0), p + BPoint(3.0, 2.0), selected ? M_BLUE_COLOR : M_DARK_GRAY_COLOR);
target->AddLine(p + BPoint(3.0, 3.0), p + BPoint(3.0, 3.0), M_MED_GRAY_COLOR);
target->EndLineArray();
}
else
{
target->BeginLineArray(7);
target->AddLine(p, p + BPoint(4.0, 0.0), M_DARK_GRAY_COLOR);
target->AddLine(p + BPoint(0.0, 1.0), p + BPoint(0.0, 4.0), M_DARK_GRAY_COLOR);
target->AddLine(p + BPoint(4.0, 1.0), p + BPoint(4.0, 4.0), M_LIGHT_GRAY_COLOR);
target->AddLine(p + BPoint(1.0, 4.0), p + BPoint(3.0, 4.0), M_LIGHT_GRAY_COLOR);
target->AddLine(p + BPoint(1.0, 1.0), p + BPoint(1.0, 3.0), M_MED_GRAY_COLOR);
target->AddLine(p + BPoint(2.0, 1.0), p + BPoint(2.0, 3.0), M_MED_GRAY_COLOR);
target->AddLine(p + BPoint(3.0, 1.0), p + BPoint(3.0, 3.0), M_MED_GRAY_COLOR);
target->EndLineArray();
}
}
else if (isOutput())
{
BRect r = targetRect;
BPoint p;
// fill rect
r = targetRect;
target->SetLowColor(M_GRAY_COLOR);
r.bottom -= 2.0;
target->FillRect(r, B_SOLID_LOW);
// draw connection point
r = targetRect;
p.Set(frame().Width() / 2.0 - 2.0, targetRect.bottom - 4.0);
target->BeginLineArray(4);
{
target->AddLine(r.LeftBottom(),
p + BPoint(0.0, 4.0),
M_DARK_GRAY_COLOR);
target->AddLine(r.LeftBottom() + BPoint(0.0, -1.0),
p + BPoint(0.0, 3.0),
M_MED_GRAY_COLOR);
target->AddLine(p + BPoint(5.0, 4.0),
r.RightBottom(),
M_DARK_GRAY_COLOR);
target->AddLine(p + BPoint(5.0, 3.0),
r.RightBottom() + BPoint(0.0, -1.0),
M_MED_GRAY_COLOR);
}
target->EndLineArray();
if (isConnected() || isConnecting())
{
target->BeginLineArray(11);
target->AddLine(p + BPoint(0.0, 4.0), p + BPoint(0.0, 4.0), M_DARK_GRAY_COLOR);
target->AddLine(p + BPoint(4.0, 4.0), p + BPoint(4.0, 4.0), M_DARK_GRAY_COLOR);
target->AddLine(p, p + BPoint(0.0, 3.0), M_DARK_GRAY_COLOR);
target->AddLine(p + BPoint(1.0, 0.0), p + BPoint(3.0, 0.0), M_DARK_GRAY_COLOR);
target->AddLine(p + BPoint(4.0, 0.0), p + BPoint(4.0, 3.0), M_LIGHT_GRAY_COLOR);
target->AddLine(p + BPoint(1.0, 1.0), p + BPoint(1.0, 1.0), M_MED_GRAY_COLOR);
target->AddLine(p + BPoint(1.0, 2.0), p + BPoint(1.0, 4.0), selected ? M_BLUE_COLOR : M_DARK_GRAY_COLOR);
target->AddLine(p + BPoint(2.0, 1.0), p + BPoint(2.0, 1.0), selected ? M_BLUE_COLOR : M_DARK_GRAY_COLOR);
target->AddLine(p + BPoint(2.0, 2.0), p + BPoint(2.0, 4.0), selected ? M_LIGHT_BLUE_COLOR : M_LIGHT_GRAY_COLOR);
target->AddLine(p + BPoint(3.0, 1.0), p + BPoint(3.0, 1.0), M_MED_GRAY_COLOR);
target->AddLine(p + BPoint(3.0, 2.0), p + BPoint(3.0, 4.0), selected ? M_BLUE_COLOR : M_DARK_GRAY_COLOR);
target->EndLineArray();
}
else
{
target->BeginLineArray(7);
target->AddLine(p + BPoint(0.0, 4.0), p + BPoint(4.0, 4.0), M_DARK_GRAY_COLOR);
target->AddLine(p, p + BPoint(0.0, 3.0), M_DARK_GRAY_COLOR);
target->AddLine(p + BPoint(1.0, 0.0), p + BPoint(3.0, 0.0), M_DARK_GRAY_COLOR);
target->AddLine(p + BPoint(4.0, 0.0), p + BPoint(4.0, 3.0), M_LIGHT_GRAY_COLOR);
target->AddLine(p + BPoint(1.0, 1.0), p + BPoint(1.0, 3.0), M_MED_GRAY_COLOR);
target->AddLine(p + BPoint(2.0, 1.0), p + BPoint(2.0, 3.0), M_MED_GRAY_COLOR);
target->AddLine(p + BPoint(3.0, 1.0), p + BPoint(3.0, 3.0), M_MED_GRAY_COLOR);
target->EndLineArray();
}
}
break;
}
}
}
void MediaJack::_updateAbbreviation()
{
D_METHOD(("MediaJack::_updateAbbreviation()\n"));
int32 offset;
m_abbreviation = "";
m_abbreviation += m_label[0];
offset = m_label.FindFirst(" ") + 1;
if ((offset > 1) && (offset < m_label.CountChars() - 1))
m_abbreviation += m_label[offset];
else
m_abbreviation += m_label[1];
offset = m_label.CountChars() - 1;
m_abbreviation += m_label[offset];
}
// -------------------------------------------------------- //
// *** internal operations (protected)
// -------------------------------------------------------- //
void MediaJack::showContextMenu(
BPoint point)
{
D_METHOD(("MediaJack::showContextMenu()\n"));
BPopUpMenu *menu = new BPopUpMenu("MediaJack PopUp", false, false, B_ITEMS_IN_COLUMN);
menu->SetFont(be_plain_font);
BMenuItem *item;
// add the "Get Info" item
if (isInput())
{
media_input input;
getInput(&input);
BMessage *message = new BMessage(InfoWindowManager::M_INFO_WINDOW_REQUESTED);
message->AddData("input", B_RAW_TYPE,
reinterpret_cast<const void *>(&input), sizeof(input));
menu->AddItem(item = new BMenuItem("Get Info", message));
}
else if (isOutput())
{
media_output output;
getOutput(&output);
BMessage *message = new BMessage(InfoWindowManager::M_INFO_WINDOW_REQUESTED);
message->AddData("output", B_RAW_TYPE,
reinterpret_cast<const void *>(&output), sizeof(output));
menu->AddItem(item = new BMenuItem("Get Info", message));
}
menu->SetTargetForItems(view());
view()->ConvertToScreen(&point);
point -= BPoint(1.0, 1.0);
menu->Go(point, true, true, true);
}
// -------------------------------------------------------- //
// *** sorting methods (friend)
// -------------------------------------------------------- //
int __CORTEX_NAMESPACE__ compareTypeAndID(
const void *lValue,
const void *rValue)
{
int retValue = 0;
const MediaJack *lJack = *(reinterpret_cast<MediaJack * const*>(reinterpret_cast<void * const*>(lValue)));
const MediaJack *rJack = *(reinterpret_cast<MediaJack * const*>(reinterpret_cast<void * const*>(rValue)));
if (lJack && rJack)
{
if (lJack->m_jackType < lJack->m_jackType)
{
return -1;
}
if (lJack->m_jackType == lJack->m_jackType)
{
if (lJack->m_index < rJack->m_index)
{
return -1;
}
else
{
return 1;
}
}
else if (lJack->m_jackType > rJack->m_jackType)
{
retValue = 1;
}
}
return retValue;
}
// END -- LiveNodeView.cpp --

View File

@ -0,0 +1,190 @@
// MediaJack.h
// c.lenz 10oct99
//
// * PURPOSE
// DiagramEndPoint derived class implementing the drawing
// code and
//
// HISTORY
//
#ifndef __MediaJack_H__
#define __MediaJack_H__
#include "DiagramEndPoint.h"
// Media Kit
#include <MediaDefs.h>
#include <MediaNode.h>
// Support Kit
#include <String.h>
class BBitmap;
#include "cortex_defs.h"
__BEGIN_CORTEX_NAMESPACE
class MediaJack : public DiagramEndPoint
{
public: // *** jack types
enum jack_t
{
M_INPUT,
M_OUTPUT
};
public: // *** constants
// [e.moon 26oct99] moved definitions to MediaJack.cpp
static float M_DEFAULT_WIDTH;
static float M_DEFAULT_HEIGHT;
static const float M_DEFAULT_GAP;
static const int32 M_MAX_ABBR_LENGTH;
public: // *** ctor/dtor
// Constructor for input jacks
MediaJack(
media_input input);
// Constructor for output jacks
MediaJack(
media_output output);
virtual ~MediaJack();
public: // *** accessors
// returns the full name of the input/output
BString name() const
{ return m_label; }
// return true if this is an input jack
bool isInput() const
{ return (m_jackType == M_INPUT); }
// copies the media_input struct into input; returns
// B_ERROR if this isn't an input jack
status_t getInput(
media_input *input) const;
// return true if this is an output jack
bool isOutput() const
{ return (m_jackType == M_OUTPUT); }
// copies the media_output struct into input; returns
// B_ERROR if this isn't an input jack
status_t getOutput(
media_output *output) const;
public: // *** derived from DiagramEndPoint/Item
// is called by the parent DiagramBox after adding endpoint
virtual void attachedToDiagram();
// is called by the parent DiagramBox just before the endpoint
// will be removed
virtual void detachedFromDiagram();
// the actual drawing code
virtual void drawEndPoint();
// returns the coordinate at which a connected MediaWire is
// supposed to start/end
virtual BPoint connectionPoint() const;
// hook called by the base class; just verifies if the jack
// type isn't equal, i.e. not connecting an input to an input
virtual bool connectionRequested(
DiagramEndPoint *which);
// displays the context menu for right-clicks
virtual void mouseDown(
BPoint point,
uint32 buttons,
uint32 clicks);
// changes the mouse cursor and prepares a tooltip
virtual void mouseOver(
BPoint point,
uint32 transit);
// changes the mouse cursor
virtual void messageDragged(
BPoint point,
uint32 transit,
const BMessage *message);
// updates the offscreen bitmap
virtual void selected();
// updates the offscreen bitmap
virtual void deselected();
// updates the offscreen bitmap
virtual void connected();
// updates the offscreen bitmap
virtual void disconnected();
public: // *** operations
// updates the jacks bitmap
void layoutChanged(
int32 layout);
// special function to be called by the parent MediaNodePanel
// for simple positioning; this method only needs to know the
// vertical offset of the jack and the left/right frame coords
// of the panel
void setPosition(
float verticalOffset,
float leftBoundary,
float rightBoundary,
BRegion *updateRegion = 0);
protected: // *** operations
// display a popup-menu at given point
void showContextMenu(
BPoint point);
private: // *** internal methods
// update the offscreen bitmap
void _updateBitmap();
// draw jack into the specified target view
void _drawInto(
BView *target,
BRect frame,
int32 layout);
// make/update an abbreviation for the jacks name
void _updateAbbreviation();
public: // *** sorting methods
// used for sorting; will put input jacks before output jacks
// and inside those sort by index
friend int compareTypeAndID(
const void *lValue,
const void *rValue);
private: // *** data
int32 m_jackType;
BBitmap *m_bitmap;
int32 m_index;
media_node m_node;
media_source m_source;
media_destination m_destination;
media_format m_format;
BString m_label;
BString m_abbreviation;
};
__END_CORTEX_NAMESPACE
#endif /* __MediaJack_H__ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,172 @@
// MediaNodePanel.h
// c.lenz 9oct99
//
// HISTORY
// c.lenz 9oct99 Begun
#ifndef __MediaNodePanel_H__
#define __MediaNodePanel_H__
// DiagramView
#include "DiagramBox.h"
// MediaRoutingView
#include "MediaJack.h"
// STL
#include <vector>
// Support Kit
#include <String.h>
#include "IStateArchivable.h"
#include "cortex_defs.h"
__BEGIN_CORTEX_NAMESPACE
class MediaIcon;
class NodeRef;
class MediaNodePanel : public DiagramBox,
public BHandler,
public IStateArchivable
{
typedef DiagramBox _inherited;
public: // *** constants
// [e.moon 26oct99] moved definitions to MediaNodePanel.cpp
static float M_DEFAULT_WIDTH;
static float M_DEFAULT_HEIGHT;
static float M_LABEL_H_MARGIN;
static float M_LABEL_V_MARGIN;
static float M_BODY_H_MARGIN;
static float M_BODY_V_MARGIN;
public: // *** accessors
NodeRef* const ref;
public: // *** ctor/dtor
MediaNodePanel(
BPoint position,
NodeRef *nodeRef);
virtual ~MediaNodePanel();
public: // *** derived from DiagramItem
virtual void attachedToDiagram();
virtual void detachedFromDiagram();
virtual void drawBox();
virtual void mouseDown(
BPoint point,
uint32 buttons,
uint32 clicks);
virtual void mouseOver(
BPoint point,
uint32 transit);
virtual void messageDropped(
BPoint point,
BMessage *message);
virtual void selected();
virtual void deselected();
public: // *** derived from BHandler
virtual void MessageReceived(
BMessage *message);
public: // *** updating
// is called by the MediaRoutingView when the layout
// (i.e. icon size, orientation, default sizes) have
// changed
void layoutChanged(
int32 layout);
// query the NodeManager for all free inputs & outputs
// and add a MediaJack instance for each; (connected
// inputs are added when the connection is reported or
// queried)
void populateInit();
// completely update the list of free input/output jacks
void updateIOJacks();
// arrange the MediaJacks in order of their IDs, resize
// the panel if more space is needed
void arrangeIOJacks();
// display popup-menu at the given point
void showContextMenu(
BPoint point);
public: // *** sorting methods
// used for sorting the panels by media_node_id
friend int compareID(
const void *lValue,
const void *rValue);
public: // *** IStateArchivable
status_t importState(
const BMessage* archive); //nyi
status_t exportState(
BMessage* archive) const; //nyi
private: // *** internal operations
// fetch node name (shortening as necessary to fit)
// and update label placement
void _prepareLabel();
// update the offscreen bitmap
void _updateBitmap();
void _drawInto(
BView *target,
BRect targetRect,
int32 layout);
void _updateIcon(
int32 layout);
private: // *** data
// a pointer to the panel's offscreen bitmap
BBitmap *m_bitmap;
BBitmap *m_icon;
BString m_label; // truncated
BString m_fullLabel; // not truncated
bool m_labelTruncated;
BPoint m_labelOffset;
BRect m_labelRect;
BRect m_bodyRect;
// cached position in the "other" layout
BPoint m_alternatePosition;
bool m_mouseOverLabel;
// [e.moon 7dec99]
static const BPoint s_invalidPosition;
};
__END_CORTEX_NAMESPACE
#endif /* __MediaNodePanel_H__ */

View File

@ -0,0 +1,34 @@
// MediaRoutingDefs.h
// c.lenz 9oct99
//
// Constants used in MediaRoutingView and friends:
// - Colors
// - Cursors
//
// HISTORY
// 6oct99 c.lenz Begun
//
#ifndef __MediaRoutingDefs_H__
#define __MediaRoutingDefs_H__
#include "cortex_defs.h"
__BEGIN_CORTEX_NAMESPACE
// -------------------------------------------------------- //
// *** cursors
// -------------------------------------------------------- //
const unsigned char M_CABLE_CURSOR [] = {
// PREAMBLE
16, 1, 0, 0,
// BITMAP
224, 0, 144, 0, 168, 0, 68, 0, 34, 0, 17, 128, 11, 64, 7, 160,
7, 208, 3, 232, 1, 244, 0, 250, 0, 125, 0, 63, 0, 30, 0, 12,
// MASK
224, 0, 240, 0, 248, 0, 124, 0, 62, 0, 31, 128, 15, 192, 7, 224,
7, 240, 3, 248, 1, 252, 0, 254, 0, 127, 0, 63, 0, 30, 0, 12
};
__END_CORTEX_NAMESPACE
#endif /* __MediaRoutingDefs_H__ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,363 @@
// MediaRoutingView.h
// c.lenz 9oct99
//
// PURPOSE
// Provide a simple interface for the BeOS/Genki media system.
// Displays all the currently running ('live') media nodes,
// and represents the connections between them visually.
//
// NOTES
//
// *** 9oct99: replaced grid-based version
//
// HISTORY
// e.moon 6may99: first stab
// c.lenz 6oct99: starting change to DiagramView impl
#ifndef __MediaRoutingView__H__
#define __MediaRoutingView__H__
// DiagramView
#include "DiagramView.h"
// Media Kit
#include "MediaDefs.h"
#include <Entry.h>
#include <List.h>
#include <Message.h>
#include "IStateArchivable.h"
#include "cortex_defs.h"
__BEGIN_CORTEX_NAMESPACE
// MediaRoutingView
class MediaNodePanel;
class MediaWire;
// NodeManager
class RouteAppNodeManager;
class NodeGroup;
class NodeRef;
class Connection;
// RouteApp
class NodeSetIOContext;
class MediaRoutingView :
public DiagramView,
public IStateArchivable {
typedef DiagramView _inherited;
public: // *** constants
// [e.moon 26oct99] moved definitions to MediaRoutingView.cpp
static float M_CLEANUP_H_GAP;
static float M_CLEANUP_V_GAP;
static float M_CLEANUP_H_MARGIN;
static float M_CLEANUP_V_MARGIN;
// [e.moon 7dec99] enum now a named type
enum layout_t
{
M_ICON_VIEW = 1,
M_MINI_ICON_VIEW
};
public: // messages
enum message_t {
// INBOUND
// "layout" int32: M_ICON_VIEW / M_MINI_ICON_VIEW
M_LAYOUT_CHANGED,
// INBOUND
M_CLEANUP_REQUESTED,
// INBOUND
// release/delete node
// "nodeID" [u]int32: node to release
M_RELEASE_NODE,
// INBOUND
M_SELECT_ALL,
// INBOUND
M_DELETE_SELECTION,
// OUTBOUND
// describes a selected node (sent to owning window)
// "nodeID" int32
M_NODE_SELECTED,
// OUTBOUND
// describes a selected group (sent to owning window)
// "groupID" int32
M_GROUP_SELECTED,
// INBOUND
// requests that the currently selected node/group be broadcast
// back to the owning window
M_BROADCAST_SELECTION,
// INBOUND
// request to change the selected nodes cycling mode (on/off)
// "cycle" bool
M_NODE_CHANGE_CYCLING,
// INBOUND
// request to change the selected nodes run mode
// "run_mode" int32
M_NODE_CHANGE_RUN_MODE,
// INBOUND
// request to start/stop the selected node(s) as a time source
// instantly
// [e.moon 5dec99]
M_NODE_START_TIME_SOURCE,
M_NODE_STOP_TIME_SOURCE,
// INBOUND
// call BControllable::StartControlPanel for the node specified
// in the field "nodeID" (int32)
// [c.lenz 24dec99]
M_NODE_START_CONTROL_PANEL,
// INBOUND
// set the given group's GROUP_LOCKED flag
// [em 1feb00]
// "groupID" int32
// "locked" bool
M_GROUP_SET_LOCKED,
// INBOUND
// open ParameterWindow for selected nodes
// [c.lenz 17feb2000]
M_NODE_TWEAK_PARAMETERS,
// INBOUND
// sent to the RouteWindow for displaying error
// messages in the status bar if available
// "text" string
// "error" bool (optional)
M_SHOW_ERROR_MESSAGE
};
public: // *** members
RouteAppNodeManager* const manager;
public: // *** ctor/dtor
MediaRoutingView(
RouteAppNodeManager *nodeManager,
BRect frame,
const char *name,
uint32 resizeMode = B_FOLLOW_ALL_SIDES);
virtual ~MediaRoutingView();
public: // *** DiagramView impl
virtual void connectionAborted(
DiagramEndPoint *fromWhich);
virtual void connectionEstablished(
DiagramEndPoint *fromWhich,
DiagramEndPoint *toWhich);
DiagramWire *createWire(
DiagramEndPoint *fromWhich,
DiagramEndPoint *woWhich);
DiagramWire *createWire(
DiagramEndPoint *fromWhich);
virtual void mouseDown(
BPoint point,
uint32 buttons,
uint32 clicks);
virtual void messageDropped(
BPoint point,
BMessage *message);
virtual void selectionChanged();
public: // *** BView impl
virtual void AttachedToWindow();
virtual void AllAttached();
virtual void DetachedFromWindow();
virtual void KeyDown(
const char *bytes,
int32 count);
virtual void Pulse();
public: // *** BHandler impl
virtual void MessageReceived(
BMessage *message);
public: // *** accessors
layout_t getLayout() const
{ return m_layout; }
public: // *** operations
// returns coordinates for a free area where the panel
// could be positioned; uses the M_CLEANUP_* settings
// and positions producers at the left, consumer at the
// right and filters in the middle
BPoint findFreePositionFor(
const MediaNodePanel *panel) const;
public: // *** IStateArchivable
status_t importState(
const BMessage* archive);
status_t exportState(
BMessage* archive) const;
// [e.moon 8dec99] subset support
status_t importStateFor(
const NodeSetIOContext* context,
const BMessage* archive);
status_t exportStateFor(
const NodeSetIOContext* context,
BMessage* archive) const;
protected: // *** operations
// adjust the default object sizes to the current
// layout and font size and rearrange if necessary
void layoutChanged(
layout_t layout);
// aligns the panels on a grid according to their node_kind
void cleanUp();
// displays a context menu at a given position
void showContextMenu(
BPoint point);
// will currently display a BAlert; this should change sometime
// in the future!
void showErrorMessage(
BString message,
status_t error);
private: // *** children management
// adds a panel representation of a live media node to the view
status_t _addPanelFor(
media_node_id id,
BPoint point);
// tries to find the panel to a given media node
status_t _findPanelFor(
media_node_id id,
MediaNodePanel **outPanel) const;
// removes the panel of a given media node
status_t _removePanelFor(
media_node_id);
// adds a wire represenation of a media kit connection
status_t _addWireFor(
Connection &connection);
// finds the ui rep of a given Connection object
status_t _findWireFor(
uint32 connectionID,
MediaWire **wire) const;
// removes the wire
status_t _removeWireFor(
uint32 connectionID);
private: // *** internal methods
// iterates through all selected MediaNodePanels and sets the
// 'cycling' state for each to cycle
void _changeCyclingForSelection(
bool cycle);
// iterates through all selected MediaNodePanels and sets the
// RunMode for each to mode; 0 is interpreted as '(same as group)'
void _changeRunModeForSelection(
uint32 mode);
void _openInfoWindowsForSelection();
void _openParameterWindowsForSelection();
void _startControlPanelsForSelection();
// tries to release every node in the current selection, or to
// disconnect wires if those were selected
void _deleteSelection();
void _addShortcuts();
void _initLayout();
// populates the view with all nodes currently in the NodeManager
void _initContent();
void _checkDroppedFile(
entry_ref *ref,
BPoint dropPoint);
void _changeBackground(
entry_ref *ref);
void _changeBackground(
rgb_color color);
// adjust scroll bar ranges
void _adjustScrollBars();
void _broadcastSelection() const;
// find & remove an entry in m_inactiveNodeState
status_t _fetchInactiveNodeState(
MediaNodePanel* forPanel,
BMessage* outMessage);
void _emptyInactiveNodeState();
private:
// the current layout
layout_t m_layout;
// current new-group-name index
uint32 m_nextGroupNumber;
// holds the id of the node instantiated last thru d&d
media_node_id m_lastDroppedNode;
// the point at which above node was dropped
BPoint m_lastDropPoint;
// holds a pointer to the currently dragged wire (if any)
MediaWire *m_draggedWire;
// stores location of the background bitmap (invalid if no
// background bitmap has been set.)
// [e.moon 1dec99]
BEntry m_backgroundBitmapEntry;
// state info for currently inactive nodes (cached from importState())
BList m_inactiveNodeState;
};
__END_CORTEX_NAMESPACE
#endif /* __MediaRoutingView_H__ */

View File

@ -0,0 +1,309 @@
// MediaWire.cpp
#include "MediaWire.h"
// InfoWindow
#include "InfoWindowManager.h"
// MediaRoutingView
#include "MediaJack.h"
#include "MediaRoutingDefs.h"
#include "MediaRoutingView.h"
// Support
#include "cortex_ui.h"
#include "MediaString.h"
// TipManager
#include "TipManager.h"
// Application Kit
#include <Application.h>
// Interface Kit
#include <MenuItem.h>
#include <PopUpMenu.h>
// Media Kit
#include <MediaDefs.h>
__USE_CORTEX_NAMESPACE
#include <Debug.h>
#define D_METHOD(x) //PRINT (x)
#define D_DRAW(x) //PRINT (x)
#define D_MOUSE(x) //PRINT (x)
// -------------------------------------------------------- //
// constants
// -------------------------------------------------------- //
const float MediaWire::M_WIRE_OFFSET = 4.0;
// -------------------------------------------------------- //
// *** ctor/dtor
// -------------------------------------------------------- //
MediaWire::MediaWire(
Connection connection,
MediaJack *outputJack,
MediaJack *inputJack)
: DiagramWire(outputJack, inputJack),
connection(connection)
{
D_METHOD(("MediaWire::MediaWire()\n"));
}
MediaWire::MediaWire(
MediaJack *jack,
bool isStartPoint)
: DiagramWire(jack, isStartPoint)
{
D_METHOD(("MediaWire::MediaWire(temp)\n"));
}
MediaWire::~MediaWire()
{
D_METHOD(("MediaWire::~MediaWire()\n"));
}
// -------------------------------------------------------- //
// *** derived from DiagramWire (public)
// -------------------------------------------------------- //
void MediaWire::attachedToDiagram()
{
D_METHOD(("MediaWire::detachedFromDiagram()\n"));
endPointMoved(startPoint());
endPointMoved(endPoint());
}
void MediaWire::detachedFromDiagram()
{
D_METHOD(("MediaWire::detachedFromDiagram()\n"));
// make sure we're no longer displaying a tooltip
TipManager *tips = TipManager::Instance();
tips->hideTip(view()->ConvertToScreen(frame()));
}
BRect MediaWire::frame() const
{
D_DRAW(("MediaWire::frame()\n"));
return m_frame;
}
float MediaWire::howCloseTo(
BPoint point) const
{
D_MOUSE(("MediaWire::howCloseTo()\n"));
if (frame().Contains(point))
{
BPoint sp = m_startPoint;
BPoint ep = m_endPoint;
BPoint so = m_startOffset;
BPoint eo = m_endOffset;
BRect wireFrame, startFrame, endFrame;
wireFrame.left = so.x < eo.x ? so.x : eo.x;
wireFrame.top = so.y < eo.y ? so.y : eo.y;
wireFrame.right = so.x > eo.x ? so.x : eo.x;
wireFrame.bottom = so.y > eo.y ? so.y : eo.y;
startFrame.Set(sp.x, sp.y, so.x, so.y);
endFrame.Set(ep.x, ep.y, eo.x, eo.y);
wireFrame.InsetBy(-1.0, -1.0);
startFrame.InsetBy(-1.0, -1.0);
endFrame.InsetBy(-1.0, -1.0);
if ((wireFrame.Width() <= 5.0) || (wireFrame.Height() <= 5.0) || startFrame.Contains(point) || endFrame.Contains(point))
{
return 1.0;
}
else
{
float length, result;
length = sqrt(pow(eo.x - so.x, 2) + pow(eo.y - so.y, 2));
result = ((so.y - point.y) * (eo.x - so.x)) - ((so.x - point.x) * (eo.y - so.y));
result = 3.0 - fabs(result / length);
return result;
}
}
return 0.0;
}
void MediaWire::drawWire()
{
D_DRAW(("MediaWire::drawWire()\n"));
rgb_color border = isSelected() ? M_BLUE_COLOR : M_DARK_GRAY_COLOR;
rgb_color fill = isSelected() ? M_LIGHT_BLUE_COLOR : M_LIGHT_GRAY_COLOR;
view()->SetPenSize(3.0);
view()->BeginLineArray(3);
view()->AddLine(m_startPoint, m_startOffset, border);
view()->AddLine(m_startOffset, m_endOffset, border);
view()->AddLine(m_endOffset, m_endPoint, border);
view()->EndLineArray();
view()->SetPenSize(1.0);
view()->BeginLineArray(3);
view()->AddLine(m_startPoint, m_startOffset, fill);
view()->AddLine(m_startOffset, m_endOffset, fill);
view()->AddLine(m_endOffset, m_endPoint, fill);
view()->EndLineArray();
}
void MediaWire::mouseDown(
BPoint point,
uint32 buttons,
uint32 clicks)
{
D_MOUSE(("MediaWire::mouseDown()\n"));
_inherited::mouseDown(point, buttons, clicks);
switch (buttons)
{
case B_SECONDARY_MOUSE_BUTTON:
{
if (clicks == 1)
{
showContextMenu(point);
}
}
}
}
void MediaWire::mouseOver(
BPoint point,
uint32 transit)
{
D_MOUSE(("MediaWire::mouseOver()\n"));
if (isDragging())
{
return;
}
switch (transit)
{
case B_ENTERED_VIEW:
{
TipManager *tips = TipManager::Instance();
BString tipText = MediaString::getStringFor(connection.format(), false);
tips->showTip(tipText.String(), view()->ConvertToScreen(frame()),
TipManager::LEFT_OFFSET_FROM_POINTER, BPoint(12.0, 8.0));
be_app->SetCursor(M_CABLE_CURSOR);
break;
}
case B_EXITED_VIEW:
{
be_app->SetCursor(B_HAND_CURSOR);
TipManager *tips = TipManager::Instance();
tips->hideTip(view()->ConvertToScreen(frame()));
break;
}
}
}
void MediaWire::selected()
{
D_METHOD(("MediaWire::selected()\n"));
if (startPoint())
{
MediaJack *outputJack = dynamic_cast<MediaJack *>(startPoint());
outputJack->select();
}
if (endPoint())
{
MediaJack *inputJack = dynamic_cast<MediaJack *>(endPoint());
inputJack->select();
}
}
void MediaWire::deselected()
{
D_METHOD(("MediaWire::deselected()\n"));
if (startPoint())
{
MediaJack *outputJack = dynamic_cast<MediaJack *>(startPoint());
outputJack->deselect();
}
if (endPoint())
{
MediaJack *inputJack = dynamic_cast<MediaJack *>(endPoint());
inputJack->deselect();
}
}
void MediaWire::endPointMoved(
DiagramEndPoint *which)
{
if (which == startPoint())
{
m_startPoint = startConnectionPoint();
switch (dynamic_cast<MediaRoutingView *>(view())->getLayout())
{
case MediaRoutingView::M_ICON_VIEW:
{
m_startOffset = m_startPoint + BPoint(M_WIRE_OFFSET, 0.0);
break;
}
case MediaRoutingView::M_MINI_ICON_VIEW:
{
m_startOffset = m_startPoint + BPoint(0.0, M_WIRE_OFFSET);
break;
}
}
m_frame.left = m_startPoint.x < m_endOffset.x ? m_startPoint.x - 2.0: m_endOffset.x - 2.0;
m_frame.top = m_startPoint.y < m_endOffset.y ? m_startPoint.y - 2.0 : m_endOffset.y - 2.0;
m_frame.right = m_startOffset.x > m_endPoint.x ? m_startOffset.x + 2.0 : m_endPoint.x + 2.0;
m_frame.bottom = m_startOffset.y > m_endPoint.y ? m_startOffset.y + 2.0 : m_endPoint.y + 2.0;
}
else if (which == endPoint())
{
m_endPoint = endConnectionPoint();
switch (dynamic_cast<MediaRoutingView *>(view())->getLayout())
{
case MediaRoutingView::M_ICON_VIEW:
{
m_endOffset = m_endPoint - BPoint(M_WIRE_OFFSET, 0.0);
break;
}
case MediaRoutingView::M_MINI_ICON_VIEW:
{
m_endOffset = m_endPoint - BPoint(0.0, M_WIRE_OFFSET);
break;
}
}
m_frame.left = m_startPoint.x < m_endOffset.x ? m_startPoint.x - 2.0: m_endOffset.x - 2.0;
m_frame.top = m_startPoint.y < m_endOffset.y ? m_startPoint.y - 2.0 : m_endOffset.y - 2.0;
m_frame.right = m_startOffset.x > m_endPoint.x ? m_startOffset.x + 2.0 : m_endPoint.x + 2.0;
m_frame.bottom = m_startOffset.y > m_endPoint.y ? m_startOffset.y + 2.0 : m_endPoint.y + 2.0;
}
}
// -------------------------------------------------------- //
// *** internal operations (protected)
// -------------------------------------------------------- //
void MediaWire::showContextMenu(
BPoint point)
{
D_METHOD(("MediaWire::showContextMenu()\n"));
BPopUpMenu *menu = new BPopUpMenu("MediaWire PopUp", false, false, B_ITEMS_IN_COLUMN);
menu->SetFont(be_plain_font);
BMenuItem *item;
// add the "Get Info" item
media_output output;
connection.getOutput(&output);
BMessage *message = new BMessage(InfoWindowManager::M_INFO_WINDOW_REQUESTED);
message->AddData("connection", B_RAW_TYPE,
reinterpret_cast<const void *>(&output), sizeof(output));
menu->AddItem(item = new BMenuItem("Get Info", message, 'I'));
// add the "Disconnect" item
menu->AddItem(item = new BMenuItem("Disconnect", new BMessage(MediaRoutingView::M_DELETE_SELECTION), 'T'));
if (connection.flags() & Connection::LOCKED)
{
item->SetEnabled(false);
}
menu->SetTargetForItems(view());
view()->ConvertToScreen(&point);
point -= BPoint(1.0, 1.0);
menu->Go(point, true, true, true);
}
// END -- MediaWire.cpp --

View File

@ -0,0 +1,115 @@
// MediaWire.h
// c.lenz 10oct99
//
// HISTORY
//
#ifndef __MediaWire_H__
#define __MediaWire_H__
// DiagramView
#include "DiagramWire.h"
// NodeManager
#include "Connection.h"
#include "cortex_defs.h"
__BEGIN_CORTEX_NAMESPACE
class MediaJack;
class MediaWire :
public DiagramWire {
typedef DiagramWire _inherited;
public: // *** constans
// [e.moon 26oct99] moved definition to MediaWire.cpp
static const float M_WIRE_OFFSET;
public: // *** ctor/dtor
// input and output jack are set connected by this constructor
// so be careful to only pass in valid pointers
MediaWire(
Connection connection,
MediaJack *outputJack,
MediaJack *inputJack);
// special constructor used only in drag&drop sessions for
// temporary visual indication of the connection process
// the isStartPoint specifies if the given EndPoint is
// supposed to be treated as start or end point
MediaWire(
MediaJack *jack,
bool isStartPoint);
virtual ~MediaWire();
public: // *** accessors
Connection connection;
public: // *** derived from DiagramWire/Item
// init the cached points and the frame rect
virtual void attachedToDiagram();
// make sure no tooltip is being displayed for this wire
// +++ DOES NOT WORK (yet)
virtual void detachedFromDiagram();
// calculates and returns the frame rectangle of the wire
virtual BRect frame() const;
// returns a value > 0.5 for points pretty much close to the
// wire
virtual float howCloseTo(
BPoint point) const;
// does the actual drawing
virtual void drawWire();
// displays the context-menu for right-clicks
virtual void mouseDown(
BPoint point,
uint32 buttons,
uint32 clicks);
// changes the mouse cursor and starts a tooltip
virtual void mouseOver(
BPoint point,
uint32 transit);
// also selects and invalidates the jacks connected by
// this wire
virtual void selected();
// also deselectes and invalidates the jacks connected
// by this wire
virtual void deselected();
// updates the cached start & end points and the frame rect
virtual void endPointMoved(
DiagramEndPoint *which = 0);
protected: // *** operations
// display a popup-menu at given point
void showContextMenu(
BPoint point);
private: // *** data members
BPoint m_startPoint;
BPoint m_endPoint;
BPoint m_startOffset;
BPoint m_endOffset;
BRect m_frame;
};
__END_CORTEX_NAMESPACE
#endif /* __MediaWire_H__ */

View File

@ -0,0 +1,243 @@
// AddOnHost.cpp
#include "AddOnHost.h"
#include "AddOnHostProtocol.h"
#include <Application.h>
#include <Debug.h>
#include <Entry.h>
#include <MediaNode.h>
#include <MediaRoster.h>
#include <Messenger.h>
#include <Path.h>
#include <Roster.h>
#include <OS.h>
#include <cstdlib>
#include <cstring>
__USE_CORTEX_NAMESPACE
// -------------------------------------------------------- //
// constants
// -------------------------------------------------------- //
BMessenger AddOnHost::s_messenger;
// -------------------------------------------------------- //
// *** static interface
// -------------------------------------------------------- //
/*static*/
status_t AddOnHost::FindInstance(
BMessenger* outMessenger) {
status_t err;
// no current app? launch one
if(!s_messenger.IsValid()) {
s_messenger = BMessenger(
addon_host::g_appSignature,
-1,
&err);
if(err < B_OK)
return err;
if(!s_messenger.IsValid())
return B_ERROR;
}
*outMessenger = s_messenger;
return B_OK;
}
/*static*/
status_t AddOnHost::Kill(
bigtime_t timeout) {
if(!s_messenger.IsValid())
return B_NOT_ALLOWED;
status_t err = kill_team(s_messenger.Team());
return err;
}
/*static*/
status_t AddOnHost::Launch(
BMessenger* outMessenger) {
if(s_messenger.IsValid())
return B_NOT_ALLOWED;
status_t err;
// find it
entry_ref appRef;
err = be_roster->FindApp(addon_host::g_appSignature, &appRef);
if(err < B_OK)
return err;
// start it
team_id team;
const char* arg = "--addon-host";
err = be_roster->Launch(
&appRef,
1,
&arg,
&team);
if(err < B_OK)
return err;
// fetch messenger to the new app and return it
s_messenger = BMessenger(
addon_host::g_appSignature,
team,
&err);
if(err < B_OK)
return err;
if(!s_messenger.IsValid())
return B_ERROR;
if(outMessenger)
*outMessenger = s_messenger;
return B_OK;
}
/*static*/
status_t AddOnHost::InstantiateDormantNode(
const dormant_node_info& info,
media_node* outNode,
bigtime_t timeout) {
status_t err;
if(!s_messenger.IsValid()) {
err = Launch(0);
if(err < B_OK) {
// give up
PRINT((
"!!! AddOnHost::InstantiateDormantNode(): Launch() failed:\n"
" %s\n",
strerror(err)));
return err;
}
}
// do it
ASSERT(s_messenger.IsValid());
BMessage request(addon_host::M_INSTANTIATE);
request.AddData("info", B_RAW_TYPE, &info, sizeof(dormant_node_info));
BMessage reply(B_NO_REPLY);
err = s_messenger.SendMessage(
&request,
&reply,
timeout,
timeout);
// PRINT((
// "### SendMessage() returned '%s'\n", strerror(err)));
if(err < B_OK) {
PRINT((
"!!! AddOnHost::InstantiateDormantNode(): SendMessage() failed:\n"
" %s\n",
strerror(err)));
return err;
}
if(reply.what == B_NO_REPLY) {
PRINT((
"!!! AddOnHost::InstantiateDormantNode(): no reply.\n"));
return B_ERROR;
}
if(reply.what == addon_host::M_INSTANTIATE_COMPLETE) {
media_node_id nodeID;
// fetch node ID
err = reply.FindInt32("node_id", &nodeID);
if(err < B_OK) {
PRINT((
"!!! AddOnHost::InstantiateDormantNode(): 'node_id' missing from reply.\n"));
return B_ERROR;
}
// fetch node
err = BMediaRoster::Roster()->GetNodeFor(nodeID, outNode);
if(err < B_OK) {
PRINT((
"!!! AddOnHost::InstantiateDormantNode(): node missing!\n"));
return B_ERROR;
}
// // now solely owned by the add-on host team
// BMediaRoster::Roster()->ReleaseNode(*outNode);
return B_OK;
}
// failed:
return (reply.FindInt32("error", &err) == B_OK) ? err : B_ERROR;
}
/*static*/
status_t AddOnHost::ReleaseInternalNode(
const live_node_info& info,
bigtime_t timeout) {
status_t err;
if(!s_messenger.IsValid()) {
err = Launch(0);
if(err < B_OK) {
// give up
PRINT((
"!!! AddOnHost::ReleaseInternalNode(): Launch() failed:\n"
" %s\n",
strerror(err)));
return err;
}
}
// do it
ASSERT(s_messenger.IsValid());
BMessage request(addon_host::M_RELEASE);
request.AddData("info", B_RAW_TYPE, &info, sizeof(live_node_info));
BMessage reply(B_NO_REPLY);
err = s_messenger.SendMessage(
&request,
&reply,
timeout,
timeout);
if(err < B_OK) {
PRINT((
"!!! AddOnHost::ReleaseInternalNode(): SendMessage() failed:\n"
" %s\n",
strerror(err)));
return err;
}
if(reply.what == B_NO_REPLY) {
PRINT((
"!!! AddOnHost::InstantiateDormantNode(): no reply.\n"));
return B_ERROR;
}
if(reply.what == addon_host::M_RELEASE_COMPLETE) {
return B_OK;
}
// failed:
return (reply.FindInt32("error", &err) == B_OK) ? err : B_ERROR;
}
// END -- AddOnHost.cpp --

View File

@ -0,0 +1,52 @@
// cortex::NodeManager::AddOnHost.h
// * PURPOSE
// Provides an interface to a separate BApplication whose
// single responsibility is to launch nodes.
// NodeManager-launched nodes now run in a separate team,
// helping to lower the likelihood of a socially maladjusted
// young node taking you out.
//
// * HISTORY
// e.moon 6nov99
#ifndef __NodeManager_AddOnHost_H__
#define __NodeManager_AddOnHost_H__
#include <Application.h>
#include <MediaAddOn.h>
#include <MediaDefs.h>
#include "cortex_defs.h"
__BEGIN_CORTEX_NAMESPACE
class AddOnHost {
public: // *** static interface
static status_t FindInstance(
BMessenger* outMessenger);
static status_t Kill(
bigtime_t timeout=B_INFINITE_TIMEOUT);
// returns B_NOT_ALLOWED if an instance has already been launched
static status_t Launch(
BMessenger* outMessenger=0);
static status_t InstantiateDormantNode(
const dormant_node_info& info,
media_node* outNode,
bigtime_t timeout=B_INFINITE_TIMEOUT);
static status_t ReleaseInternalNode(
const live_node_info& info,
bigtime_t timeout=B_INFINITE_TIMEOUT);
static BMessenger s_messenger;
private: // implementation
friend class _AddOnHostApp;
};
__END_CORTEX_NAMESPACE
#endif /*__NodeManager_AddOnHost_H__*/

View File

@ -0,0 +1,179 @@
// Connection.cpp
// e.moon 25jun99
#include "Connection.h"
#include "NodeManager.h"
#include "NodeRef.h"
#if CORTEX_XML
#include "ExportContext.h"
#include "MediaFormatIO.h"
#include "xml_export_utils.h"
#endif /*CORTEX_XML*/
#include <Debug.h>
// -------------------------------------------------------- //
__USE_CORTEX_NAMESPACE
// -------------------------------------------------------- //
// ctor/dtor
// -------------------------------------------------------- //
Connection::~Connection() {
// PRINT(("~Connection(): '%s'->'%s'\n",
// outputName(), inputName()));
//
// deallocate hints
if(m_outputHint) delete m_outputHint;
if(m_inputHint) delete m_inputHint;
}
Connection::Connection() :
m_disconnected(true),
m_id(0),
m_outputHint(0),
m_inputHint(0) {}
Connection::Connection(
uint32 id,
media_node srcNode,
const media_source& src,
const char* outputName,
media_node destNode,
const media_destination& dest,
const char* inputName,
const media_format& format,
uint32 flags) :
m_disconnected(false),
m_id(id),
m_sourceNode(srcNode),
m_source(src),
m_outputName(outputName),
m_outputHint(0),
m_destinationNode(destNode),
m_destination(dest),
m_inputName(inputName),
m_inputHint(0),
m_format(format),
m_flags(flags) {
ASSERT(id);
m_requestedFormat.type = B_MEDIA_NO_TYPE;
}
Connection::Connection(
const Connection& clone) {
operator=(clone);
}
Connection& Connection::operator=(
const Connection& clone) {
m_disconnected = clone.m_disconnected;
m_id = clone.m_id;
m_sourceNode = clone.m_sourceNode;
m_source = clone.m_source;
m_outputName = clone.m_outputName;
m_outputHint = (clone.m_outputHint ?
new endpoint_hint(
clone.m_outputHint->name.String(),
clone.m_outputHint->format) :
0);
m_destinationNode = clone.m_destinationNode;
m_destination = clone.m_destination;
m_inputName = clone.m_inputName;
m_inputHint = (clone.m_inputHint ?
new endpoint_hint(
clone.m_inputHint->name.String(),
clone.m_inputHint->format) :
0);
m_format = clone.m_format;
m_flags = clone.m_flags;
m_requestedFormat = clone.m_requestedFormat;
return *this;
}
// input/output access [e.moon 14oct99]
status_t Connection::getInput(
media_input* outInput) const {
if(!isValid())
return B_ERROR;
outInput->node = m_destinationNode;
strcpy(outInput->name, m_inputName.String());
outInput->format = format();
outInput->source = m_source;
outInput->destination = m_destination;
return B_OK;
}
status_t Connection::getOutput(
media_output* outOutput) const {
if(!isValid())
return B_ERROR;
outOutput->node = m_sourceNode;
strcpy(outOutput->name, m_outputName.String());
outOutput->format = format();
outOutput->source = m_source;
outOutput->destination = m_destination;
return B_OK;
}
// hint access
status_t Connection::getOutputHint(
const char** outName,
media_format* outFormat) const {
if(!m_outputHint)
return B_NOT_ALLOWED;
*outName = m_outputHint->name.String();
*outFormat = m_outputHint->format;
return B_OK;
}
status_t Connection::getInputHint(
const char** outName,
media_format* outFormat) const {
if(!m_inputHint)
return B_NOT_ALLOWED;
*outName = m_inputHint->name.String();
*outFormat = m_inputHint->format;
return B_OK;
}
void Connection::setOutputHint(
const char* origName,
const media_format& origFormat) {
if(m_outputHint) delete m_outputHint;
m_outputHint = new endpoint_hint(origName, origFormat);
}
void Connection::setInputHint(
const char* origName,
const media_format& origFormat) {
if(m_inputHint) delete m_inputHint;
m_inputHint = new endpoint_hint(origName, origFormat);
}
// [e.moon 8dec99]
void Connection::setRequestedFormat(
const media_format& reqFormat) {
m_requestedFormat = reqFormat;
}
// END -- Connection.cpp --

View File

@ -0,0 +1,188 @@
// Connection.h (Cortex)
// * PURPOSE
// Represents a general connection between two media nodes.
//
// * NOTES 13aug99
// Connection is undergoing massive resimplification(TM).
// 1) It's now intended to be stored and passed by value; synchronization
// and reference issues are no more.
// 2) It now refers to the participatory nodes by ID, not pointer. This
// makes the nodes slightly more cumbersome to look up, but makes
// Connection completely 'safe': an outdated instance doesn't contain
// any dangerous information.
//
// * NOTES 29jul99
// 1) For completeness, a release() or disconnect() method would be nice. Problems?
// 2) How will connections between 'external' nodes be denoted? For example,
// the audioMixer->audioOutput connection must not be broken EVER. Other external
// connections might be manually broken, but should be left alone when the
// NodeManager quits (whereas all internal connections need to be removed by
// the dtor.) This implies two flags: 'internal' and 'locked'...
//
// * HISTORY
// e.moon 25jun99 Begun
#ifndef __Connection_H__
#define __Connection_H__
#include <Debug.h>
#include <MediaNode.h>
#include <String.h>
#include "cortex_defs.h"
__BEGIN_CORTEX_NAMESPACE
class NodeManager;
class NodeGroup;
class NodeRef;
class Connection {
// rather incestuous set of classes we've got here...
friend NodeRef;
friend NodeManager;
public: // *** types & constants
enum flag_t {
// connection should be removed automatically when the NodeManager
// is destroyed
INTERNAL = 1<<1,
// connection must never be removed
LOCKED = 1<<2
};
public: // *** dtor/user-level ctors
virtual ~Connection();
Connection();
Connection(
const Connection& clone); //nyi
Connection& operator=(
const Connection& clone); //nyi
public: // *** accessors
uint32 id() const { return m_id; }
bool isValid() const { return
m_sourceNode != media_node::null &&
m_destinationNode != media_node::null &&
!m_disconnected; }
// changed 13aug99
media_node_id sourceNode() const { return m_sourceNode.node; }
const media_source& source() const { return m_source; }
const char* outputName() const { return m_outputName.String(); }
// changed 13aug99
media_node_id destinationNode() const { return m_destinationNode.node; }
const media_destination& destination() const { return m_destination; }
const char* inputName() const { return m_inputName.String(); }
const media_format& format() const { return m_format; }
uint32 flags() const { return m_flags; }
// input/output access [e.moon 14oct99]
status_t getInput(
media_input* outInput) const;
status_t getOutput(
media_output* outOutput) const;
// hint access
status_t getOutputHint(
const char** outName,
media_format* outFormat) const;
status_t getInputHint(
const char** outName,
media_format* outFormat) const;
const media_format& requestedFormat() const { return m_requestedFormat; }
protected: // *** general ctor accessible to subclasses &
// cortex::NodeManager
// id must be non-0
Connection(
uint32 id,
media_node srcNode,
const media_source& src,
const char* outputName,
media_node destNode,
const media_destination& dest,
const char* inputName,
const media_format& format,
uint32 flags);
// if any information about the pre-connection (free) output format
// is known, call this method. this info may be useful in
// finding the output to re-establish the connection later on.
void setOutputHint(
const char* origName,
const media_format& origFormat);
// if any information about the pre-connection (free) input format
// is known, call this method. this info may be useful in
// finding the output to re-establish the connection later on.
void setInputHint(
const char* origName,
const media_format& origFormat);
// [e.moon 8dec99]
void setRequestedFormat(
const media_format& reqFormat);
private: // *** members
// info that may be useful for reconstituting a particular
// connection later on.
struct endpoint_hint {
endpoint_hint(const char* _name, const media_format& _format) :
name(_name), format(_format) {}
BString name;
media_format format;
};
// waiting to die?
bool m_disconnected;
// unique connection ID
uint32 m_id;
// [e.moon 14oct99] now stores media_nodes
// source/output info
media_node m_sourceNode;
media_source m_source;
BString m_outputName;
endpoint_hint* m_outputHint;
// dest/input info
media_node m_destinationNode;
media_destination m_destination;
BString m_inputName;
endpoint_hint* m_inputHint;
// connection format
media_format m_format;
// behaviour modification
uint32 m_flags;
// [e.moon 8dec99] initial requested format
media_format m_requestedFormat;
};
__END_CORTEX_NAMESPACE
#endif /*__Connection_H__*/

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,620 @@
// NodeGroup.h (Cortex/NodeManager)
//
// * PURPOSE
// Represents a logical group of media kit nodes.
// Provides group-level operations (transport control
// and serialization, for example.)
//
// * NODE SYNC/LOOPING +++++
//
// 22jul99
// ----------------------------
// +++++
// - cycling support needs to be thoroughly defined; ie. what
// can it do, and what can it NOT do.
//
// For example, a change in node latency will likely confuse
// the cycling mechanism. Is there any possible way to avoid
// this without explicit help from the node? The roster sends
// no notification, and even if it did the message might not
// arrive in time. Polling is possible, but ...ick.
//
// [this is assuming the 'just-in-time' cycling mechanism:
// seeks are queued as late as possible; if the latency increases
// significantly, the seek will be queued TOO late and the
// node will get out of sync.]
//
// ----------------------------
// 14jul99
//
// How about handling addition of a node to a group while it's
// playing? The "effects insert" scenario:
//
// 1) you have a producer node, followed by (0..*) filters in
// series, followed by a consumer
// 2) the transport is started
// 3) you wish to connect a new filter in the chain with minimal
// interruption -- preferably a pause in output, resuming
// with media time & perf. time still in sync.
//
// Process:
// - instantiate the filter & do any setup needed
// - [tmStart = current media time; tpStart = current perf. time]
// - stop the transport; break the connection at the insert
// point and connect the new filter
// - calculate the new latency
// - cue a seek for all nodes:
// to tmStart+latency+pad,
// at tpStart+latency+pad - 1
// - cue a start for all nodes:
// at tpStart+latency+pad
//
// (pad is the estimated amount of time taken to stop, break
// & make connections, etc. It can probably be determined in
// a test loop.)
//
// With the current NodeManager grouping behavior, this operation
// would split the NodeGroup, then (provided the filter insertion
// works) join it again. This is such a common procedure, though,
// that an 'insert' operation at the NodeManager level would be
// pretty damn handy. So would a 'remove insert' operation (given
// a node with a single input and output, connect its input's source
// to its output's destination, with the original format.)
//
// * HISTORY
// e.moon 29sep99 Made thread control variables 'volatile'.
// e.moon 6jul99 Begun
#ifndef __NodeGroup_H__
#define __NodeGroup_H__
#include "ObservableHandler.h"
#include "observe.h"
#include "ILockable.h"
// +++++ [e.moon 3dec99] need to include these for calcLatencyFn impl
// +++++ YUCK
#include "NodeRef.h"
#include <MediaRoster.h>
#include <vector>
#include <Locker.h>
#include <MediaNode.h>
#include <String.h>
class BTimeSource;
#include "cortex_defs.h"
#if CORTEX_XML
#include "IPersistent.h"
#endif
__BEGIN_CORTEX_NAMESPACE
class NodeManager;
class NodeRef;
class GroupCycleThread;
class NodeGroup :
public ObservableHandler,
public ILockable {
typedef ObservableHandler _inherited;
friend NodeManager;
friend NodeRef;
public: // *** messages
enum message_t {
// groupID: int32
// target: BMessenger
M_OBSERVER_ADDED =NodeGroup_message_base,
M_OBSERVER_REMOVED,
M_RELEASED,
// groupID: int32
// nodeID: int32
M_NODE_ADDED,
M_NODE_REMOVED,
// groupID: int32
// transportState: int32
// ++++++ include the following?
// runMode: int32
// [mediaStart: bigtime_t] only sent if changed
// [mediaEnd: bigtime_t] only sent if changed
M_TRANSPORT_STATE_CHANGED,
// groupID: int32
// timeSourceID: int32 +++++ should be a node?
M_TIME_SOURCE_CHANGED,
// groupID: int32
// runMode: int32
M_RUN_MODE_CHANGED,
// Set a new time source:
// timeSourceNode: media_node
M_SET_TIME_SOURCE,
// Set a run mode
// runMode: int32 (must be a valid run mode -- not 0!)
M_SET_RUN_MODE,
// Set new start/end position:
// position: bigtime_t (int64)
M_SET_START_POSITION, //K
M_SET_END_POSITION, //L
// Transport controls:
M_PREROLL,
M_START,
M_STOP,
M_ROLL // [e.moon 11oct99]
};
public: // *** types
// transport state
enum transport_state_t {
TRANSPORT_INVALID,
TRANSPORT_STOPPED,
TRANSPORT_STARTING,
TRANSPORT_RUNNING,
TRANSPORT_ROLLING, // [e.moon 11oct99]
TRANSPORT_STOPPING
};
// [em 1feb00] flags
enum flag_t {
// no new nodes may be added
GROUP_LOCKED = 1
};
public: // *** ctor/dtor
// free the group, including all nodes within it
// (this call will result in the eventual deletion of the object.)
// returns B_OK on success; B_NOT_ALLOWED if release() has
// already been called; other error codes if the Media Roster
// call fails.
status_t release();
// call release() rather than deleting NodeGroup objects
virtual ~NodeGroup();
public: // *** const accessors
// [e.moon 13oct99] moved method definition here to keep inline
// in the face of a balky PPC compiler
inline uint32 id() const { return m_id; }
public: // *** content accessors
// name access
const char* name() const;
status_t setName(const char* name);
// node access
// - you can write-lock the group during sets of calls to these methods;
// this ensures that the node set won't change. The methods do lock
// the group internally, so locking isn't explicitly required.
uint32 countNodes() const;
NodeRef* nodeAt(
uint32 index) const;
// add/remove nodes:
// - you may only add a node with no current group.
// - nodes added during playback will be started;
// nodes removed during playback will be stopped (unless
// the NO_START_STOP transport restriction flag is set
// for a given node.)
status_t addNode(
NodeRef* node);
status_t removeNode(
NodeRef* node);
status_t removeNode(
uint32 index);
// group flag access
uint32 groupFlags() const;
status_t setGroupFlags(
uint32 flags);
// returns true if one or more nodes in the group have cycling
// enabled, and the start- and end-positions are valid
bool canCycle() const;
public: // *** TRANSPORT POSITIONING
// Fetch the current transport state
transport_state_t transportState() const;
// Set the starting media time:
// This is the point at which playback will begin in any media
// files/documents being played by the nodes in this group.
// When cycle mode is enabled, this is the point to which each
// node will be seek'd at the end of each cycle (loop).
//
// The starting time can't be changed in the B_OFFLINE run mode
// (this call will return an error.)
status_t setStartPosition(
bigtime_t start); //nyi
// Fetch the starting position:
bigtime_t startPosition() const; //nyi
// Set the ending media time:
// This is the point at which playback will end relative to
// media documents begin played by the nodes in this group;
// in cycle mode, this specifies the loop point. If the
// ending time is less than or equal to the starting time,
// the transport will continue until stopped manually.
// If the end position is changed while the transport is playing,
// it must take effect retroactively (if it's before the current
// position and looping is enabled, all nodes must 'warp' to
// the proper post-loop position.) +++++ echk!
//
// The ending time can't be changed if run mode is B_OFFLINE and
// the transport is running (this call will return an error.)
status_t setEndPosition(
bigtime_t end); //nyi
// Fetch the end position:
// Note that if the end position is less than or equal to the start
// position, it's ignored.
bigtime_t endPosition() const; //nyi
public: // *** TRANSPORT OPERATIONS
// Preroll the group:
// Seeks, then prerolls, each node in the group (honoring the
// NO_SEEK and NO_PREROLL flags.) This ensures that the group
// can start as quickly as possible.
//
// Returns B_NOT_ALLOWED if the transport is running.
status_t preroll();
// Start all nodes in the group:
// Nodes with the NO_START_STOP flag aren't molested.
status_t start();
// Stop all nodes in the group:
// Nodes with the NO_START_STOP flag aren't molested.
status_t stop();
// Roll all nodes in the group:
// Queues a start and stop atomically (via BMediaRoster::RollNode()).
// Returns B_NOT_ALLOWED if endPosition <= startPosition.
status_t roll();
public: // *** TIME SOURCE & RUN-MODE OPERATIONS
// getTimeSource():
// returns B_ERROR if no time source has been set; otherwise,
// returns the node ID of the current time source for all
// nodes in the group.
//
// setTimeSource():
// Calls SetTimeSourceFor() on every node in the group.
// The group must be stopped; B_NOT_ALLOWED will be returned
// if the state is TRANSPORT_RUNNING or TRANSPORT_ROLLING.
status_t getTimeSource(
media_node* outTimeSource) const;
status_t setTimeSource(
const media_node& timeSource);
// run mode access:
// Sets the default run mode for the group. This will be
// applied to every node with a wildcard (0) run mode.
//
// Special case: if the run mode is B_OFFLINE, it will be
// applied to all nodes in the group.
status_t setRunMode(
BMediaNode::run_mode mode); //nyi
BMediaNode::run_mode runMode() const; //nyi
public: // *** BHandler
virtual void MessageReceived(
BMessage* message);
#if CORTEX_XML
public: // *** IPersistent
// +++++
// Default constructor
NodeGroup();
#endif /*CORTEX_XML*/
public: // *** IObservable: [19aug99]
virtual void observerAdded(
const BMessenger& observer);
virtual void observerRemoved(
const BMessenger& observer);
virtual void notifyRelease();
virtual void releaseComplete();
public: // *** ILockable: [21jul99]
// Each NodeGroup has a semaphore (BLocker).
// Only WRITE locking is allowed!
bool lock(
lock_t type=WRITE,
bigtime_t timeout=B_INFINITE_TIMEOUT);
bool unlock(
lock_t type=WRITE);
bool isLocked(
lock_t type=WRITE) const;
protected: // *** ctor (accessible to NodeManager)
NodeGroup(
const char* name,
NodeManager* manager,
BMediaNode::run_mode runMode=BMediaNode::B_INCREASE_LATENCY);
protected: // *** internal operations
static uint32 NextID();
protected: // *** ref->group communication (LOCK REQUIRED)
// When a NodeRef's cycle state (ie. looping or not looping)
// changes, it must pass that information on via this method.
// +++++ group cycle thread
void _refCycleChanged(
NodeRef* ref);
// when a cycling node's latency changes, call this method.
// +++++ shouldn't there be a general latency-change hook?
void _refLatencyChanged(
NodeRef* ref);
// when a NodeRef receives notification that it has been stopped,
// but is labeled as still running, it must call this method.
// [e.moon 11oct99: roll/B_OFFLINE support]
void _refStopped(
NodeRef* ref);
private: // *** transport helpers (LOCK REQUIRED)
// Preroll all nodes in the group; this is the implementation
// of preroll().
// *** this method should not be called from the transport thread
// (since preroll operations can block for a relatively long time.)
status_t _preroll();
// Start all nodes in the group; this is the implementation of
// start().
//
// (this may be called from the transport thread or from
// an API-implementation method.)
status_t _start();
// Stop all nodes in the group; this is the implementation of
// stop(). Fails if the run mode is B_OFFLINE; use _roll() instead
// in that case.
//
// (this may be called from the transport thread or from
// an API-implementation method.)
status_t _stop();
// Roll all nodes in the group; this is the implementation of
// roll().
//
// (this may be called from the transport thread or from
// an API-implementation method.)
status_t _roll(); //nyi [11oct99 e.moon]
// State transition; notify listeners
inline void _changeState(
transport_state_t to);
// Enforce a state transition, and notify listeners
inline void _changeState(
transport_state_t from,
transport_state_t to);
private: // *** transport thread guts
// void _initPort();
// void _initThread();
//
// static status_t _TransportThread(void* user);
// void _transportThread();
// functor: calculates latency of each node it's handed, caching
// the largest one found; includes initial latency if nodes report it.
class calcLatencyFn { public:
bigtime_t& maxLatency;
calcLatencyFn(bigtime_t& _m) : maxLatency(_m) {}
void operator()(NodeRef* r) {
ASSERT(r);
if(!(r->node().kind & B_BUFFER_PRODUCER)) {
// node can't incur latency
return;
}
bigtime_t latency;
status_t err =
BMediaRoster::Roster()->GetLatencyFor(
r->node(),
&latency);
if(err < B_OK) {
PRINT((
"* calcLatencyFn: GetLatencyFor() failed: %s\n",
strerror(err)));
return;
}
bigtime_t add;
err = BMediaRoster::Roster()->GetInitialLatencyFor(
r->node(),
&add);
if(err < B_OK) {
PRINT((
"* calcLatencyFn: GetInitialLatencyFor() failed: %s\n",
strerror(err)));
}
else
latency += add;
if(latency > maxLatency)
maxLatency = latency;
}
};
friend class calcLatencyFn;
protected: // *** cycle thread & helpers (LOCK REQUIRED)
// set up the cycle thread (including its kernel port)
status_t _initCycleThread();
// shut down the cycle thread/port
status_t _destroyCycleThread();
// 1) do the current positions specify a valid cycle region?
// 2) are any nodes in the group cycle-enabled?
bool _cycleValid();
// initialize the next cycle
void _cycleInit(
bigtime_t startTime);
// add a ref to the cycle set (in proper order, based on latency)
void _cycleAddRef(
NodeRef* ref);
// remove a ref from the cycle set
void _cycleRemoveRef(
NodeRef* ref);
// fetches the next cycle boundary (performance time of next loop)
bigtime_t _cycleBoundary() const;
// cycle thread impl.
static status_t _CycleThread(void* user);
void _cycleThread();
// cycle service: seek all nodes & initiate next cycle
void _handleCycleService();
private: // *** members
// lock
mutable BLocker m_lock;
// parent object
NodeManager* m_manager;
// unique group ID (non-0)
const uint32 m_id;
static uint32 s_nextID;
// group name
BString m_name;
// group contents
typedef vector<NodeRef*> node_set;
node_set m_nodes;
// flags & state
uint32 m_flags;
transport_state_t m_transportState;
// default run mode applied to all nodes with a wildcard (0)
// run mode.
BMediaNode::run_mode m_runMode;
// current time source
media_node m_timeSource;
BTimeSource* m_timeSourceObj;
// slated to die?
bool m_released;
// ---------------------------
// 10aug99
// cycle thread implementation
// ---------------------------
enum cycle_thread_msg_t {
_CYCLE_STOP,
_CYCLE_END_CHANGED,
_CYCLE_LATENCY_CHANGED
};
thread_id m_cycleThread;
port_id m_cyclePort;
bool m_cycleThreadDone;
// when did the current cycle begin?
bigtime_t m_cycleStart;
// performance time at which the current cycle settings will
// be applied (ie. the first seek should be queued)
bigtime_t m_cycleDeadline;
// performance time at which the next cycle begins
bigtime_t m_cycleBoundary;
// the set of nodes currently in cycle mode
// ordered by latency (largest first)
node_set m_cycleNodes;
// count of nodes that have completed this cycle
// (once complete, deadline and boundary are reset, and any
// deferred start/end positions are applied.)
uint32 m_cycleNodesComplete;
// max latency of any cycling node
bigtime_t m_cycleMaxLatency;
// the minimum allowed loop time
static const bigtime_t s_minCyclePeriod = 1000LL;
// the amount of time to allow for Media Roster calls
// (StartNode, SeekNode, etc) to be handled
static const bigtime_t s_rosterLatency = 1000LL; // +++++ probably high
// position state
volatile bigtime_t m_startPosition;
volatile bigtime_t m_endPosition;
// changed positions deferred in cycle mode
volatile bool m_newStart;
volatile bigtime_t m_newStartPosition;
volatile bool m_newEnd;
volatile bigtime_t m_newEndPosition;
};
__END_CORTEX_NAMESPACE
#endif /*__NodeGroup_H__*/

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,558 @@
// NodeManager.h (Cortex)
//
// * PURPOSE
// Provides a Media Kit application with a straightforward
// way to keep track of media nodes and the connections
// between them. Nodes are collected into sets via the
// NodeGroup class; these sets can be controlled in tandem.
//
// * GROUPING NOTES
// A new group is created with the following information:
// - time source (defaults to the DAC time source)
// - a user-provided name
//
// New nodes can be added to a group via NodeGroup methods. When a
// node is added to a group, it will automatically be assigned the
// group's time source. Unless the node has a run mode set, it will
// also be assigned the group's run mode. (If the group is in B_OFFLINE
// mode, this will be assigned to all nodes even if they specify something
// else.) If a node is added to a group whose transport is running, it
// will automatically be seeked and started (unless one or both of those
// operations has been disabled.)
//
// * SYNCHRONIZATION NOTES
// Each NodeManager object, including all the NodeGroup and NodeRef
// objects in its care, is synchronized by a single semaphore.
// Most operations in these three classes require that the object
// be locked.
//
// * UI HOOKS
// NodeManager resends any Media Roster messages to all observers
// *after* processing them: the NodeRef corresponding to a newly-
// created node, for example, must exist by the time that a
// NodeManager observer receives B_MEDIA_NODE_CREATED.
//
//
// * HISTORY
// e.moon 7nov99 1) added hooks for Media Roster message processing
// 2) improved NodeGroup handling
// e.moon 6nov99 safe node instantiation (via addon-host
// application)
// e.moon 11aug99 Expanded findConnection() methods.
// e.moon 6jul99 Begun
#ifndef __NodeManager_H__
#define __NodeManager_H__
#include "ILockable.h"
#include "ObservableLooper.h"
#include "observe.h"
#include <Looper.h>
#include <MediaDefs.h>
#include <MediaNode.h>
#include <vector>
#include <map>
class BMediaRoster;
#include "cortex_defs.h"
__BEGIN_CORTEX_NAMESPACE
class Connection;
class NodeGroup;
class NodeRef;
class NodeManager :
public ObservableLooper,
public ILockable {
// primary parent class:
typedef ObservableLooper _inherited;
friend NodeGroup;
friend NodeRef;
friend Connection;
public: // *** messages
// [13aug99]
// NodeManager retransmits Media Roster messages to its listeners,
// after processing each message.
//
/// B_MEDIA_CONNECTION_BROKEN
// This message, as sent by the Media Roster, contains only
// source/destination information. NodeManager adds these fields
// to the message:
// __connection_id: (uint32) id of the Connection; 0 if no
// matching Connection was found.
// __source_node_id: media_node_id of the node corresponding to
// the source; 0 if no matching Connection was
// found.
// __destination_node_id: media_node_id of the node corresponding to
// the source; 0 if no matching Connection was
// found.
//
// B_MEDIA_FORMAT_CHANGED
// NodeManager add these fields as above:
// __connection_id
// __source_node_id
// __destination_node_id
enum outbound_message_t {
M_OBSERVER_ADDED =NodeManager_message_base,
M_OBSERVER_REMOVED,
M_RELEASED,
// groupID: int32
M_GROUP_CREATED,
M_GROUP_DELETED,
// groupID: int32 x2 (the first is the original)
M_GROUP_SPLIT,
// groupID: int32 x2
M_GROUPS_MERGED
};
public: // *** default group names
static const char* const s_defaultGroupPrefix;
static const char* const s_timeSourceGroup;
static const char* const s_audioInputGroup;
static const char* const s_videoInputGroup;
static const char* const s_audioMixerGroup;
static const char* const s_videoOutputGroup;
public: // *** hooks
// [e.moon 7nov99] these hooks are called during processing of
// BMediaRoster messages, before any notification is sent to
// observers. For example, if a B_MEDIA_NODES_CREATED message
// were received describing 3 new nodes, nodeCreated() would be
// called 3 times before the notification was sent.
virtual void nodeCreated(
NodeRef* ref);
virtual void nodeDeleted(
const NodeRef* ref);
virtual void connectionMade(
Connection* connection);
virtual void connectionBroken(
const Connection* connection);
virtual void connectionFailed(
const media_output & output,
const media_input & input,
const media_format & format,
status_t error);
public: // *** ctor/dtor
NodeManager(
bool useAddOnHost=false);
// don't directly delete NodeManager;
// use IObservable::release()
virtual ~NodeManager();
public: // *** const members
// cached roster pointer
::BMediaRoster* const roster;
public: // *** operations
// * ACCESS
// fetches NodeRef corresponding to a given ID; returns
// B_BAD_VALUE if no matching entry was found (and writes
// a 0 into the provided pointer.)
status_t getNodeRef(
media_node_id id,
NodeRef** outRef) const;
// [13aug99]
// fetches Connection corresponding to a given source/destination
// on a given node. Returns an invalid connection and B_BAD_VALUE
// if no matching connection was found.
status_t findConnection(
media_node_id node,
const media_source& source,
Connection* outConnection) const;
status_t findConnection(
media_node_id node,
const media_destination& destination,
Connection* outConnection) const;
// [e.moon 28sep99]
// fetches a Connection matching the given source and destination
// nodes. Returns an invalid connection and B_BAD_VALUE if
// no matching connection was found
status_t findConnection(
media_node_id sourceNode,
media_node_id destinationNode,
Connection* outConnection) const;
// [e.moon 28sep99]
// tries to find a route from 'nodeA' to 'nodeB'; returns
// true if one exists, false if not. If nodeA and nodeB
// are the same node, only returns true if it's actually
// connected to itself.
bool findRoute(
media_node_id nodeA,
media_node_id nodeB);
private:
// implementation of above
class _find_route_state;
bool _find_route_recurse(
NodeRef* origin,
media_node_id target,
_find_route_state* state);
public:
// fetches Connection corresponding to a given source or
// destination; Returns an invalid connection and B_BAD_VALUE if
// none found.
// * Note: this is the slowest possible way to look up a
// connection. Since the low-level source/destination
// structures don't include a node ID, and a destination
// port can differ from its node's control port, a linear
// search of all known connections is performed. Only
// use these methods if you have no clue what node the
// connection corresponds to.
status_t findConnection(
const media_source& source,
Connection* outConnection) const;
status_t findConnection(
const media_destination& destination,
Connection* outConnection) const;
// fetch NodeRefs for system nodes (if a particular node doesn't
// exist, these methods return 0)
NodeRef* audioInputNode() const;
NodeRef* videoInputNode() const;
NodeRef* audioMixerNode() const;
NodeRef* audioOutputNode() const;
NodeRef* videoOutputNode() const;
// * GROUP CREATION
NodeGroup* createGroup(
const char* name,
BMediaNode::run_mode runMode=BMediaNode::B_INCREASE_LATENCY);
// fetch groups by index
// - you can write-lock the manager during sets of calls to these methods;
// this ensures that the group set won't change. The methods do lock
// the group internally, so locking isn't explicitly required.
uint32 countGroups() const;
NodeGroup* groupAt(
uint32 index) const;
// look up a group by unique ID; returns B_BAD_VALUE if no
// matching group was found
status_t findGroup(
uint32 id,
NodeGroup** outGroup) const;
// look up a group by name; returns B_NAME_NOT_FOUND if
// no group matching the name was found.
status_t findGroup(
const char* name,
NodeGroup** outGroup) const;
// merge the given source group to the given destination;
// empties and releases the source group
status_t mergeGroups(
NodeGroup* sourceGroup,
NodeGroup* destinationGroup);
// [e.moon 28sep99]
// split group: given two nodes currently in the same group
// that are not connected (directly OR indirectly),
// this method removes outsideNode, and all nodes connected
// to outsideNode, from the common group. These nodes are
// then added to a new group, returned in 'outGroup'. The
// new group has " split" appended to the end of the original
// group's name.
//
// Returns B_NOT_ALLOWED if any of the above conditions aren't
// met (ie. the nodes are in different groups or an indirect
// route exists from one to the other), or B_OK if the group
// was split successfully.
status_t splitGroup(
NodeRef* insideNode,
NodeRef* outsideNode,
NodeGroup** outGroup);
// * INSTANTIATION & CONNECTION
// Use these calls rather than the associated BMediaRoster()
// methods to assure that the nodes and connections you set up
// can be properly serialized & reconstituted.
// basic BMediaRoster::InstantiateDormantNode() wrapper
// - writes a 0 into *outRef if the instantiation fails
// - [e.moon 23oct99]
// returns B_BAD_INDEX if InstantiateDormantNode() returns
// success, but doesn't hand back a viable media_node
// - [e.moon 6nov99] +++++ 'distributed' instantiate:
// wait for an external app to create the node; allow for
// failure.
status_t instantiate(
const dormant_node_info& info,
NodeRef** outRef=0,
bigtime_t timeout=B_INFINITE_TIMEOUT,
uint32 nodeFlags=0);
// SniffRef/Instantiate.../SetRefFor: a one-call interface
// to create a node capable of playing a given media file.
// - writes a 0 into *outRef if the instantiation fails; on the
// other hand, if instantiation succeeds, but SetRefFor() fails,
// a NodeRef will still be returned.
status_t instantiate(
const entry_ref& file,
uint64 requireNodeKinds,
NodeRef** outRef,
bigtime_t timeout=B_INFINITE_TIMEOUT,
uint32 nodeFlags=0,
bigtime_t* outDuration=0);
// use this method to reference nodes created within your
// application. These nodes can't be automatically reconstituted
// by the cortex serializer yet.
status_t reference(
BMediaNode* node,
NodeRef** outRef,
uint32 nodeFlags=0);
// the most flexible form of connect(): set the template
// format as you would for BMediaRoster::Connect().
status_t connect(
const media_output& output,
const media_input& input,
const media_format& templateFormat,
Connection* outConnection=0);
// format-guessing form of connect(): tries to find
// a common format between output & input before connection;
// returns B_MEDIA_BAD_FORMAT if no common format type found.
//
// NOTE: the specifics of the input and output formats are ignored;
// this method only looks at the format type, and properly
// handles wildcards at that level (B_MEDIA_NO_TYPE).
status_t connect(
const media_output& output,
const media_input& input,
Connection* outConnection=0);
// disconnects the connection represented by the provided
// Connection object. if successful, returns B_OK.
status_t disconnect(
const Connection& connection);
public: // *** node/connection iteration
// *** MUST BE LOCKED for any of these calls
// usage:
// For the first call, pass 'cookie' a pointer to a void* set to 0.
// Returns B_BAD_INDEX when the set of nodes has been exhausted (and
// invalidates the cookie, so don't try to use it after this point.)
status_t getNextRef(
NodeRef** outRef,
void** cookie);
// if you want to stop iterating, call this method to avoid leaking
// memory
void disposeRefCookie(
void** cookie);
status_t getNextConnection(
Connection* outConnection,
void** cookie);
void disposeConnectionCookie(
void** cookie);
public: // *** BHandler impl
void MessageReceived(BMessage* message); //nyi
public: // *** IObservable hooks
virtual void observerAdded(
const BMessenger& observer);
virtual void observerRemoved(
const BMessenger& observer);
virtual void notifyRelease();
virtual void releaseComplete();
public: // *** ILockable impl.
virtual bool lock(
lock_t type=WRITE,
bigtime_t timeout=B_INFINITE_TIMEOUT);
virtual bool unlock(
lock_t type=WRITE);
virtual bool isLocked(
lock_t type=WRITE) const;
protected: // *** internal operations (LOCK REQUIRED)
void _initCommonNodes();
void _addRef(
NodeRef* ref);
void _removeRef(
media_node_id id);
// create, add, return a NodeRef for the given external node;
// must not already exist
NodeRef* _addRefFor(
const media_node& node,
uint32 nodeFlags,
uint32 nodeImplFlags=0);
void _addConnection(
Connection* connection);
void _removeConnection(
const Connection& connection);
void _addGroup(
NodeGroup* group);
void _removeGroup(
NodeGroup* group);
// dtor helpers
inline void _clearGroup(
NodeGroup* group);
inline void _freeConnection(
Connection* connection);
// message handlers
// now returns B_OK iff the message should be relayed to observers
// [e.moon 11oct99]
inline status_t _handleNodesCreated(
BMessage* message);
inline void _handleNodesDeleted(
BMessage* message);
inline void _handleConnectionMade(
BMessage* message);
inline void _handleConnectionBroken(
BMessage* message);
inline void _handleFormatChanged(
BMessage* message);
// return flags appropriate for an external
// node with the given 'kind'
inline uint32 _userFlagsForKind(
uint32 kind);
inline uint32 _implFlagsForKind(
uint32 kind);
// [e.moon 28sep99] latency updating
// These methods must set the recording-mode delay for
// any B_RECORDING nodes they handle.
// +++++ abstract to 'for each' and 'for each from'
// methods (template or callback?)
// refresh cached latency for every node in the given group
// (or all nodes if no group given.)
inline void _updateLatencies(
NodeGroup* group =0);
// refresh cached latency for every node attached to
// AND INCLUDING the given origin node.
// if 'recurse' is true, affects indirectly attached
// nodes as well.
inline void _updateLatenciesFrom(
NodeRef* origin,
bool recurse =false);
// a bit of unpleasantness [e.moon 13oct99]
inline void _lockAllGroups();
inline void _unlockAllGroups();
private: // *** internal messages
enum int_message_t {
// groupID: int32
_M_GROUP_RELEASED = NodeManager_int_message_base
};
private: // *** members
// the main NodeRef store
typedef map<media_node_id, NodeRef*> node_ref_map;
node_ref_map m_nodeRefMap;
// the Connection stores (connections are indexed by both
// source and destination node ID)
typedef multimap<media_node_id, Connection*> con_map;
con_map m_conSourceMap;
con_map m_conDestinationMap;
// the NodeGroup store
typedef vector<NodeGroup*> node_group_set;
node_group_set m_nodeGroupSet;
// common system nodes
NodeRef* m_audioInputNode;
NodeRef* m_videoInputNode;
NodeRef* m_audioMixerNode;
NodeRef* m_audioOutputNode;
NodeRef* m_videoOutputNode;
// next unique connection ID
uint32 m_nextConID;
// false until the first 'nodes created' message is
// received from the Media Roster, and pre-existing connection
// info is filled in:
bool m_existingNodesInit;
// true if nodes should be launched via an external application
// (using AddOnHost)
bool m_useAddOnHost;
};
__END_CORTEX_NAMESPACE
#endif /*__NodeManager_H__*/

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,656 @@
// NodeRef.h (Cortex/NodeManager)
//
// * PURPOSE
// Represents a NodeManager reference to a live Media Kit Node.
//
// * FEATURES UNDER CONSIDERATION +++++
// - lazy referencing: m_released becomes m_referenced; only reference
// externally created nodes once they've been grouped or connected.
// +++++ or disconnected? keep a'thinkin...
// - expose dormant_node_info
//
// * HISTORY
// e.moon 11aug99 Added kind().
// e.moon 9aug99 Moved position & cycle threads into NodeRef;
// no more 'group transport thread'.
// e.moon 25jun99 Begun
#ifndef __NodeRef_H__
#define __NodeRef_H__
#include <MediaAddOn.h>
#include <MediaNode.h>
#include <String.h>
#include <vector>
#include "ILockable.h"
#include "MultiInvoker.h"
#include "ObservableHandler.h"
#include "observe.h"
#include "cortex_defs.h"
__BEGIN_CORTEX_NAMESPACE
class Connection;
class NodeManager;
class NodeGroup;
class NodeSyncThread;
class NodeRef :
public ObservableHandler,
protected ILockable {
typedef ObservableHandler _inherited;
friend NodeManager;
friend NodeGroup;
public: // *** messages
enum message_t {
// OUTBOUND
// nodeID: int32
// target: BMessenger
M_OBSERVER_ADDED =NodeRef_message_base,
M_OBSERVER_REMOVED,
M_RELEASED,
// OUTBOUND
// nodeID: int32
// groupID: int32
M_GROUP_CHANGED,
// nodeID: int32
// runMode: int32
M_RUN_MODE_CHANGED,
// +++++
M_INPUTS_CHANGED, //nyi
M_OUTPUTS_CHANGED, //nyi
// OUTBOUND
// * only sent to position listeners
// nodeID: int32
// when: int64
// position: int64
M_POSITION,
// INBOUND
// runMode: int32
// delay: int64 (bigtime_t; applies only to B_RECORDING mode)
M_SET_RUN_MODE,
// INBOUND
M_PREROLL,
// INBOUND
// "cycling"; bool (OR "be:value"; int32)
M_SET_CYCLING,
// OUTBOUND
// "cycling"; bool
M_CYCLING_CHANGED
};
public: // *** flags
enum flag_t {
// node-level transport restrictions
NO_START_STOP = 1<<1,
NO_SEEK = 1<<2,
NO_PREROLL = 1<<3,
// [e.moon 28sep99] useful for misbehaved nodes
NO_STOP = 1<<4,
// [e.moon 11oct99]
// Disables media-roster connection (which currently
// only makes use of B_MEDIA_NODE_STOPPED.)
// This flag may become deprecated as the Media Kit
// evolves (ie. more node-level notifications come
// along.)
NO_ROSTER_WATCH = 1<<5,
// [e.moon 14oct99]
// Disables position reporting (via BMediaRoster::SyncToNode().)
// Some system-provided nodes tend to explode when SyncToNode() is
// called on them (like the video-file player in BeOS R4.5.2).
NO_POSITION_REPORTING = 1<<6
};
public: // *** dtor
// free the node (this call will result in the eventual
// deletion of the object.)
// returns B_OK on success; B_NOT_ALLOWED if release() has
// already been called; other error codes if the Media Roster
// call fails.
status_t release();
// call release() rather than deleting NodeRef objects
virtual ~NodeRef();
public: // *** const accessors
// [e.moon 13oct99] moved method definitions here to keep inline
// in the face of a balky PPC compiler
inline const media_node& node() const { return m_info.node; }
inline uint32 kind() const { return m_info.node.kind; }
inline const live_node_info& nodeInfo() const { return m_info; }
inline const char* name() const { return m_info.name; }
inline media_node_id id() const { return m_info.node.node; }
public: // *** member access
// turn cycle mode (looping) on or off
void setCycling(
bool cycle);
bool isCycling() const;
// is the node running?
bool isRunning() const;
// was the node created via NodeManager::instantiate()?
bool isInternal() const;
// fetch the group, or 0 if the node is ungrouped.
NodeGroup* group() const;
// flag access
uint32 flags() const;
void setFlags(
uint32 flags);
// [e.moon 29sep99]
// access addon-hint info
// - returns B_BAD_VALUE if not an add-on node created by this NodeManager
status_t getDormantNodeInfo(
dormant_node_info* outInfo);
// [e.moon 29sep99]
// access file being played
// - returns B_BAD_VALUE if not an add-on node created by this NodeManager,
// or if the node has no associated file
status_t getFile(
entry_ref* outFile);
// [e.moon 8dec99]
// set file to play
status_t setFile(
const entry_ref& file,
bigtime_t* outDuration=0); //nyi
// [e.moon 23oct99]
// returns true if the media_node has been released (call releaseNode() to
// make this happen.)
bool isNodeReleased() const;
// now implemented by ObservableHandler [20aug99]
// // has this reference been released?
// bool isReleased() const;
public: // *** run-mode operations
void setRunMode(
uint32 runMode,
bigtime_t delay=0LL);
uint32 runMode() const;
bigtime_t recordingDelay() const;
// calculates the minimum amount of delay needed for
// B_RECORDING mode
// +++++ 15sep99: returns biggest_output_buffer_duration * 2
// +++++ 28sep99: adds downstream latency
bigtime_t calculateRecordingModeDelay(); //nyi
public: // *** connection access
// connection access: vector versions
status_t getInputConnections(
vector<Connection>& ioConnections,
media_type filterType=B_MEDIA_UNKNOWN_TYPE) const;
status_t getOutputConnections(
vector<Connection>& ioConnections,
media_type filterType=B_MEDIA_UNKNOWN_TYPE) const;
// connection access: flat array versions
status_t getInputConnections(
Connection* outConnections,
int32 maxConnections,
int32* outNumConnections,
media_type filterType=B_MEDIA_UNKNOWN_TYPE) const;
status_t getOutputConnections(
Connection* outConnections,
int32 maxConnections,
int32* outNumConnections,
media_type filterType=B_MEDIA_UNKNOWN_TYPE) const;
// +++++ connection matching by source/destination +++++
public: // *** position reporting/listening
bool positionReportsEnabled() const;
void enablePositionReports();
void disablePositionReports();
// Fetch the approximate current position:
// Returns the last reported position, and the
// performance time at which that position was reached. If the
// transport has never been started, the start position and
// a performance time of 0 will be returned. If position updating
// isn't currently enabled, returns B_NOT_ALLOWED.
status_t getLastPosition(
bigtime_t* outPosition,
bigtime_t* outPerfTime) const;
// Subscribe to regular position reports:
// Position reporting isn't rolled into the regular observer
// interface because a large number of messages are generated
// (the frequency can be changed; see below.)
status_t addPositionObserver(
BHandler* handler);
status_t removePositionObserver(
BHandler* handler);
// Set how often position updates will be sent:
// Realistically, period should be > 10000 or so.
status_t setPositionUpdatePeriod(
bigtime_t period);
bigtime_t positionUpdatePeriod() const;
public: // *** BMediaRoster wrappers & convenience methods
// release the media node
// (if allowed, will trigger the release/deletion of this object)
status_t releaseNode();
// calculate total (internal + downstream) latency for this node
status_t totalLatency(
bigtime_t* outLatency) const;
// retrieve input/output matching the given destination/source.
// returns B_MEDIA_BAD_[SOURCE | DESTINATION] if the destination
// or source don't correspond to this node.
status_t findInput(
const media_destination& forDestination,
media_input* outInput) const;
status_t findOutput(
const media_source& forSource,
media_output* outOutput) const;
// endpoint matching (given name and/or format as 'hints').
// If no hints are given, returns the first free endpoint, if
// any exist.
// returns B_ERROR if no matching endpoint is found.
status_t findFreeInput(
media_input* outInput,
media_type type=B_MEDIA_UNKNOWN_TYPE,
const char* name=0) const;
status_t findFreeInput(
media_input* outInput,
const media_format* format,
const char* name=0) const;
status_t findFreeOutput(
media_output* outOutput,
media_type type=B_MEDIA_UNKNOWN_TYPE,
const char* name=0) const;
status_t findFreeOutput(
media_output* outOutput,
const media_format* format,
const char* name=0) const;
// node endpoint access: vector versions (wrappers for BMediaRoster
// calls.)
status_t getFreeInputs(
vector<media_input>& ioInputs,
media_type filterType=B_MEDIA_UNKNOWN_TYPE) const;
status_t getConnectedInputs(
vector<media_input>& ioInputs,
media_type filterType=B_MEDIA_UNKNOWN_TYPE) const;
status_t getFreeOutputs(
vector<media_output>& ioOutputs,
media_type filterType=B_MEDIA_UNKNOWN_TYPE) const;
status_t getConnectedOutputs(
vector<media_output>& ioOutputs,
media_type filterType=B_MEDIA_UNKNOWN_TYPE) const;
// node endpoint access: array versions (wrappers for BMediaRoster
// calls.)
status_t getFreeInputs(
media_input* outInputs,
int32 maxInputs,
int32* outNumInputs,
media_type filterType=B_MEDIA_UNKNOWN_TYPE) const;
status_t getConnectedInputs(
media_input* outInputs,
int32 maxInputs,
int32* outNumInputs) const;
status_t getFreeOutputs(
media_output* outOutputs,
int32 maxOutputs,
int32* outNumOutputs,
media_type filterType=B_MEDIA_UNKNOWN_TYPE) const;
status_t getConnectedOutputs(
media_output* outOutputs,
int32 maxOutputs,
int32* outNumOutputs) const;
public: // *** BHandler:
virtual void MessageReceived(
BMessage* message);
public: // *** IObservable: [20aug99]
virtual void observerAdded(
const BMessenger& observer);
virtual void observerRemoved(
const BMessenger& observer);
virtual void notifyRelease();
virtual void releaseComplete();
protected: // *** ILockable
// Only WRITE locking is allowed!
bool lock(
lock_t type=WRITE,
bigtime_t timeout=B_INFINITE_TIMEOUT);
bool unlock(
lock_t type=WRITE);
bool isLocked(
lock_t type=WRITE) const;
protected: // *** ctor (accessible to NodeManager)
// throws runtime_error
NodeRef(
const media_node& node,
NodeManager* manager,
uint32 userFlags,
uint32 implFlags);
protected: // *** endpoint-fixing operations (no lock required)
// 'fix' (fill in node if needed) sets of inputs/outputs
void _fixInputs(
media_input* inputs,
int32 count) const;
void _fixInputs(
vector<media_input>& inputs) const;
void _fixOutputs(
media_output* outputs,
int32 count) const;
void _fixOutputs(
vector<media_output>& outputs) const;
protected: // *** internal/NodeManager operations (LOCK REQUIRED)
// call after instantiation to register info used to select and
// create this add-on node
void _setAddonHint(
const dormant_node_info* info,
const entry_ref* file=0);
// call to set a new group; if 0, the node must have no
// connections
void _setGroup(
NodeGroup* group);
// *** NodeGroup API ***
// 9aug99: moved from NodeGroup
// [e.moon 13oct99] removed inlines for the sake of PPC sanity
// initialize the given node's transport-state members
// (this may be called from the transport thread or from
// an API-implementation method.)
status_t _initTransportState();
status_t _setTimeSource(
media_node_id timeSourceID);
status_t _setRunMode(
const uint32 runMode,
bigtime_t delay=0LL);
status_t _setRunModeAuto(
const uint32 runMode);
// seek and preroll the given node.
// *** this method should not be called from the transport thread
// (since preroll operations can block for a relatively long time.)
//
// returns B_NOT_ALLOWED if the node is running, or if its NO_PREROLL
// flag is set; otherwise, returns B_OK on success or a Media Roster
// error.
status_t _preroll(
bigtime_t position);
// seek the given node if possible
// (this may be called from the transport thread or from
// an API-implementation method.)
status_t _seek(
bigtime_t position,
bigtime_t when);
// seek the given (stopped) node
// (this may be called from the transport thread or from
// an API-implementation method.)
status_t _seekStopped(
bigtime_t position);
// start the given node, if possible & necessary, at
// the given time
// (this may be called from the transport thread or from
// an API-implementation method.)
status_t _start(
bigtime_t when);
// stop the given node (which may or may not still be
// a member of this group.)
// (this may be called from the transport thread or from
// an API-implementation method.)
status_t _stop();
// roll the given node, if possible.
// (this may be called from the transport thread or from
// an API-implementation method.)
status_t _roll(
bigtime_t start,
bigtime_t stop,
bigtime_t position);
// refresh the node's current latency; if I reference
// a B_RECORDING node, update its 'producer delay'.
status_t _updateLatency();
// +++++ this method may not be needed 10aug99 +++++
// Figure the earliest time at which the given node can be started.
// Also calculates the position at which it should start from to
// play in sync with other nodes in the group, if the transport is
// running; if stopped, *outPosition will be set to the current
// start position.
// Pass the estimated amount of time needed to prepare the
// node for playback (ie. preroll & a little fudge factor) in
// startDelay.
//
// (this may be called from the transport thread or from
// an API-implementation method.)
status_t _calcStartTime(
bigtime_t startDelay,
bigtime_t* outTime,
bigtime_t* outPosition); //nyi
// *** Position reporting ***
// callers: _start(), _roll(), enablePositionReports()
status_t _startPositionThread();
// callers: _stop(), disablePositionReports(), dtor
status_t _stopPositionThread();
// [e.moon 14oct99] handle a report
status_t _handlePositionUpdate(
bigtime_t perfTime,
bigtime_t position);
// callers: _handlePositionUpdate
// (schedules a position update for the given time and position;
// if the position overlaps a cycle, adjusts time & position
// so that the notification is sent at the cycle point.)
status_t _schedulePositionUpdate(
bigtime_t when,
bigtime_t position);
// callers: _handlePositionUpdate, _initPositionThread()
// Send a message to all position observers
status_t _notifyPosition(
bigtime_t when,
bigtime_t position);
private: // *** members
// the node manager
NodeManager* m_manager;
// owning (parent) group; may be 0 if node is not connected.
// A connected node always has a group, since groups allow transport
// operations. New groups are created as necessary.
NodeGroup* m_group;
// the node's state
live_node_info m_info;
// user-definable transport behavior
uint32 m_flags;
// private/implementation flags
enum impl_flag_t {
// the node was created by NodeManager
_INTERNAL = 1<<1,
// the node should NOT be released when this instance is destroyed
_NO_RELEASE = 1<<2,
// notification of the node's instantiation has been received
// [e.moon 11oct99]
_CREATE_NOTIFIED = 1<<3
};
uint32 m_implFlags;
// takes BMediaNode::run_mode values or 0 (wildcard:
// group run mode used instead)
// May not be B_OFFLINE; that must be specified at the group level.
uint32 m_runMode;
// only valid if m_runMode is BMediaNode::B_RECORDING
bigtime_t m_recordingDelay;
// Media Roster connection [e.moon 11oct99]
bool m_watching;
// hint information: this info is serialized with the object
// to provide 'hints' towards properly finding the same add-on
// node later on. If no hint is provided, the node is assumed
// to be external to (not created by) the NodeManager.
struct addon_hint;
addon_hint* m_addonHint;
// * position listening:
// - moved from NodeGroup 9aug99
bool m_positionReportsEnabled;
bool m_positionReportsStarted;
bigtime_t m_positionUpdatePeriod;
static const bigtime_t s_defaultPositionUpdatePeriod = 50000LL;
MultiInvoker m_positionInvoker;
bigtime_t m_tpLastPositionUpdate;
bigtime_t m_lastPosition;
// * synchronization threads
// only active if position listening has been enabled
NodeSyncThread* m_positionThread;
// // only active if this node is cycling (looping)
// CycleSyncThread* m_cycleSyncThread;
// +++++ 10aug99: moved back to NodeGroup
private: // *** transport state members
// is this node running?
bool m_running;
// has the media_node (NOT this object) been released?
bool m_nodeReleased;
// is this node supposed to loop?
bool m_cycle;
// has the node been prepared to start?
bool m_prerolled;
// when was the node started?
bigtime_t m_tpStart;
// if the node has been prerolled, m_tpLastSeek will be 0 but
// m_lastSeekPos will reflect the node's prerolled position
bigtime_t m_tpLastSeek;
bigtime_t m_lastSeekPos;
// has a stop event been queued? [e.moon 11oct99]
bigtime_t m_stopQueued;
// last known latency for this node
bigtime_t m_latency;
};
__END_CORTEX_NAMESPACE
#endif /*__NodeRef_H__*/

View File

@ -0,0 +1,182 @@
// NodeSyncThread.cpp
#include "NodeSyncThread.h"
#include <cstring>
#include <Debug.h>
#include <MediaRoster.h>
__USE_CORTEX_NAMESPACE
// -------------------------------------------------------- //
// *** dtor/ctors
// -------------------------------------------------------- //
NodeSyncThread::~NodeSyncThread() {
status_t err;
// clean up
if(m_thread) {
err = kill_thread(m_thread);
if(err < B_OK)
PRINT((
"! ~NodeSyncThread(): kill_thread(%ld):\n"
" %s\n",
m_thread,
strerror(err)));
// +++++ is a wait_for_thread() necessary?
}
if(m_port) {
err = delete_port(m_port);
if(err < B_OK)
PRINT((
"! ~NodeSyncThread(): delete_port(%ld):\n"
" %s\n",
m_port,
strerror(err)));
}
if(m_portBuffer)
delete [] m_portBuffer;
if(m_messenger)
delete m_messenger;
}
NodeSyncThread::NodeSyncThread(
const media_node& node,
BMessenger* messenger) :
m_node(node),
m_messenger(messenger),
m_syncInProgress(false),
m_thread(0),
m_port(0),
m_portBuffer(0),
m_portBufferSize(sizeof(_sync_op)) {
ASSERT(m_messenger);
m_portBuffer = new char[m_portBufferSize];
m_port = create_port(
m_portBufferSize * 16,
"NodeSyncThread___port");
ASSERT(m_port >= B_OK);
m_thread = spawn_thread(
&_Sync,
"NodeSyncThread",
B_DISPLAY_PRIORITY,
this);
ASSERT(m_thread >= B_OK);
resume_thread(m_thread);
}
// -------------------------------------------------------- //
// *** operations
// -------------------------------------------------------- //
// trigger a sync operation: when 'perfTime' arrives
// for the node, a M_SYNC_COMPLETE message with the given
// position value will be sent, unless the sync operation
// times out, in which case M_TIMED_OUT will be sent.
status_t NodeSyncThread::sync(
bigtime_t perfTime,
bigtime_t position,
bigtime_t timeout) {
status_t err;
if(m_syncInProgress)
return B_NOT_ALLOWED;
_sync_op op = {perfTime, position, timeout};
err = write_port(
m_port,
M_TRIGGER,
&op,
sizeof(_sync_op));
return err;
}
// -------------------------------------------------------- //
// *** guts
// -------------------------------------------------------- //
/*static*/
status_t NodeSyncThread::_Sync(
void* cookie) {
((NodeSyncThread*)cookie)->_sync();
return B_OK;
}
// THREAD BODY
//
void NodeSyncThread::_sync() {
ASSERT(m_port >= B_OK);
ASSERT(m_messenger);
bool done = false;
while(!done) {
// WAIT FOR A REQUEST
int32 code;
ssize_t readCount = read_port(
m_port,
&code,
m_portBuffer,
m_portBufferSize);
if(readCount < B_OK) {
PRINT((
"! NodeSyncThread::_sync(): read_port():\n"
" %s\n",
strerror(readCount)));
continue;
}
if(code != M_TRIGGER) {
PRINT((
"! NodeSyncThread::sync(): unknown message code %ld\n",
code));
continue;
}
// SERVICE THE REQUEST
const _sync_op& op = *(_sync_op*)m_portBuffer;
// pre-fill the message
BMessage m(M_SYNC_COMPLETE);
m.AddInt32("nodeID", m_node.node);
m.AddInt64("perfTime", op.targetTime);
m.AddInt64("position", op.position);
// sync
status_t err = BMediaRoster::Roster()->SyncToNode(
m_node,
op.targetTime,
op.timeout);
// deliver reply
if(err < B_OK) {
m.what = M_SYNC_FAILED;
m.AddInt32("error", err);
}
err = m_messenger->SendMessage(&m);
if(err < B_OK) {
PRINT((
"! NodeSyncThread::_sync(): m_messenger->SendMessage():\n"
" %s\n",
strerror(err)));
}
}
}
// END -- NodeSyncThread.cpp --

View File

@ -0,0 +1,98 @@
// NodeSyncThread.h [rewrite 14oct99]
// * PURPOSE
// Provide continuous synchronization notices on
// a particular BMediaNode. Notification is sent
// to a provided BMessenger.
//
// As long as a NodeSyncThread object exists its thread
// is running. The thread blocks indefinitely, waiting
// for a message to show up on an internal port.
//
// Sync-notice requests (via the +++++ sync() operation)
// trigger a message sent to that port. The thread wakes
// up, then calls BMediaRoster::SyncToNode() to wait
// until a particular performace time arrives for that node.
//
// If SyncToNode() times out, an M_TIMED_OUT message is sent;
// otherwise, an M_SYNC_COMPLETE message is sent.
//
// * HISTORY
// e.moon 14oct99 Rewrite begun.
#ifndef __NodeSyncThread_H__
#define __NodeSyncThread_H__
#include <MediaNode.h>
#include <Messenger.h>
#include <OS.h>
#include "cortex_defs.h"
__BEGIN_CORTEX_NAMESPACE
class NodeSyncThread {
public: // *** messages
enum message_t {
// 'nodeID' (int32) media_node_id value
// 'perfTime' (int64) the performance time
// 'position' (int64) corresponding (caller-provided) position
M_SYNC_COMPLETE =NodeSyncThread_message_base,
// 'nodeID' (int32) media_node_id value
// 'error' (int32) status_t value from SyncToNode()
// 'perfTime' (int64) the performance time
// 'position' (int64) corresponding (caller-provided) position
M_SYNC_FAILED
};
public: // *** dtor/ctors
virtual ~NodeSyncThread();
NodeSyncThread(
const media_node& node,
BMessenger* messenger);
public: // *** operations
// trigger a sync operation: when 'perfTime' arrives
// for the node, a M_SYNC_COMPLETE message with the given
// position value will be sent, unless the sync operation
// times out, in which case M_TIMED_OUT will be sent.
status_t sync(
bigtime_t perfTime,
bigtime_t position,
bigtime_t timeout);
private:
// the node to watch
media_node m_node;
// the messenger to inform
BMessenger* m_messenger;
// if the thread is running, it has exclusive write access
// to this flag.
volatile bool m_syncInProgress;
// thread guts
thread_id m_thread;
port_id m_port;
char* m_portBuffer;
ssize_t m_portBufferSize;
enum _op_codes {
M_TRIGGER
};
struct _sync_op {
bigtime_t targetTime;
bigtime_t position;
bigtime_t timeout;
};
static status_t _Sync(
void* cookie);
void _sync();
};
__END_CORTEX_NAMESPACE
#endif /*__NodeSyncThread_H__*/

View File

@ -0,0 +1,62 @@
// node_manager_impl.h
// * PURPOSE
// Helper classes & functions used by NodeManager,
// NodeGroup, and NodeRef.
// * HISTORY
// e.moon 10jul99 Begun
#ifndef __node_manager_impl_H__
#define __node_manager_impl_H__
#include "Connection.h"
#include "ILockable.h"
#include "cortex_defs.h"
__BEGIN_CORTEX_NAMESPACE
inline void assert_locked(const ILockable* target) {
ASSERT(target);
ASSERT(target->isLocked());
}
//
//// functor: disconnect Connection
//
//class disconnectFn { public:
// NodeManager* manager;
// disconnectFn(NodeManager* _manager) : manager(_manager) {}
// void operator()(Connection* c) {
// ASSERT(c);
// ASSERT(c->isValid());
//
// status_t err = manager->disconnect(c);
//
//#if DEBUG
// if(err < B_OK)
// PRINT((
// "* disconnect():\n"
// " output %s:%s\n"
// " input %s:%s\n"
// " error '%s'\n\n",
// c->sourceNode()->name(), c->outputName(),
// c->destinationNode()->name(), c->inputName(),
// strerror(err)));
//#endif
// }
//};
//
//// functor: release NodeRef or NodeGroup (by pointer)
//// +++++ currently no error checking; however, the only error
//// release() is allowed to return is that the object has
//// already been released.
//
//template <class T>
//class releaseFn { public:
// void operator()(T* object) {
// ASSERT(object);
// object->release();
// }
//};
__END_CORTEX_NAMESPACE
#endif /*__node_manager_impl_H__*/

View File

@ -0,0 +1,157 @@
// ParameterContainerView.cpp
#include "ParameterContainerView.h"
// Interface Kit
#include <ScrollBar.h>
#include <View.h>
__USE_CORTEX_NAMESPACE
#include <Debug.h>
#define D_ALLOC(x) //PRINT (x)
#define D_HOOK(x) //PRINT (x)
#define D_INTERNAL(x) //PRINT (x)
// -------------------------------------------------------- //
// *** ctor/dtor
// -------------------------------------------------------- //
ParameterContainerView::ParameterContainerView(
BRect dataRect,
BView *target) :
BView(
target->Frame(),
"ParameterContainerView",
B_FOLLOW_ALL_SIDES,
B_FRAME_EVENTS|B_WILL_DRAW),
m_target(target),
m_dataRect(dataRect),
m_boundsRect(Bounds()),
m_hScroll(0),
m_vScroll(0) {
D_ALLOC(("ParameterContainerView::ParameterContainerView()\n"));
BView* wrapper = new BView(
m_target->Bounds(), 0, B_FOLLOW_ALL_SIDES, B_WILL_DRAW|B_FRAME_EVENTS);
m_target->SetResizingMode(B_FOLLOW_LEFT|B_FOLLOW_TOP);
m_target->MoveTo(B_ORIGIN);
wrapper->AddChild(m_target);
AddChild(wrapper);
BRect b = wrapper->Frame();
ResizeTo(
b.Width() + B_V_SCROLL_BAR_WIDTH,
b.Height() + B_H_SCROLL_BAR_HEIGHT);
BRect hsBounds = b;
hsBounds.left--;
hsBounds.top = hsBounds.bottom + 1;
hsBounds.right++;
hsBounds.bottom = hsBounds.top + B_H_SCROLL_BAR_HEIGHT + 1;
m_hScroll = new BScrollBar(
hsBounds,
"hScrollBar",
m_target,
0, 0, B_HORIZONTAL);
AddChild(m_hScroll);
BRect vsBounds = b;
vsBounds.left = vsBounds.right + 1;
vsBounds.top--;
vsBounds.right = vsBounds.right + B_V_SCROLL_BAR_WIDTH + 1;
vsBounds.bottom++;
m_vScroll = new BScrollBar(
vsBounds,
"vScrollBar",
m_target,
0, 0, B_VERTICAL);
AddChild(m_vScroll);
SetViewColor(tint_color(ui_color(B_PANEL_BACKGROUND_COLOR), B_LIGHTEN_1_TINT));
_updateScrollBars();
}
ParameterContainerView::~ParameterContainerView() {
D_ALLOC(("ParameterContainerView::~ParameterContainerView()\n"));
}
// -------------------------------------------------------- //
// *** BScrollView impl
// -------------------------------------------------------- //
void ParameterContainerView::FrameResized(
float width,
float height) {
D_HOOK(("ParameterContainerView::FrameResized()\n"));
BView::FrameResized(width, height);
// BRect b = ChildAt(0)->Frame();
// printf("param view:\n");
// b.PrintToStream();
// printf("hScroll:\n");
// m_target->ScrollBar(B_HORIZONTAL)->Frame().PrintToStream();
// printf("vScroll:\n");
// m_target->ScrollBar(B_VERTICAL)->Frame().PrintToStream();
// fprintf(stderr, "m: %.1f,%.1f c: %.1f,%.1f)\n", width, height, b.Width(),b.Height());
if(height > m_boundsRect.Height()) {
Invalidate(BRect(
m_boundsRect.left, m_boundsRect.bottom, m_boundsRect.right, m_boundsRect.top+height));
}
if(width > m_boundsRect.Width()) {
Invalidate(BRect(
m_boundsRect.right, m_boundsRect.top, m_boundsRect.left+width, m_boundsRect.bottom));
}
m_boundsRect = Bounds();
_updateScrollBars();
}
// -------------------------------------------------------- //
// *** internal operations
// -------------------------------------------------------- //
void ParameterContainerView::_updateScrollBars() {
D_INTERNAL(("ParameterContainerView::_updateScrollBars()\n"));
// fetch the vertical ScrollBar
if (m_vScroll) {
float height = Bounds().Height() - B_H_SCROLL_BAR_HEIGHT;
// Disable the ScrollBar if the window is large enough to display
// the entire parameter view
D_INTERNAL((" -> dataRect.Height() = %f scrollView.Height() = %f\n", m_dataRect.Height(), height));
if (height > m_dataRect.Height()) {
D_INTERNAL((" -> disable vertical scroll bar\n"));
m_vScroll->SetRange(0.0, 0.0);
m_vScroll->SetProportion(1.0);
}
else {
D_INTERNAL((" -> enable vertical scroll bar\n"));
m_vScroll->SetRange(m_dataRect.top, m_dataRect.bottom - height);
m_vScroll->SetProportion(height / m_dataRect.Height());
}
}
if (m_hScroll) {
float width = Bounds().Width() - B_V_SCROLL_BAR_WIDTH;
// Disable the ScrollBar if the view is large enough to display
// the entire data-rect
D_INTERNAL((" -> dataRect.Width() = %f scrollView.Width() = %f\n", m_dataRect.Width(), width));
if (width > m_dataRect.Width()) {
D_INTERNAL((" -> disable horizontal scroll bar\n"));
m_hScroll->SetRange(0.0, 0.0);
m_hScroll->SetProportion(1.0);
}
else {
D_INTERNAL((" -> enable horizontal scroll bar\n"));
m_hScroll->SetRange(m_dataRect.left, m_dataRect.right - width);
m_hScroll->SetProportion(width / m_dataRect.Width());
}
}
}
// END -- ParameterContainerView.cpp --

View File

@ -0,0 +1,56 @@
// ParameterContainerView.h (Cortex/ParameterWindow)
//
// * PURPOSE
//
// * TODO
//
// * HISTORY
// c.lenz 16feb2000 Begun
//
#ifndef __ParameterContainerView_H__
#define __ParameterContainerView_H__
// Interface Kit
#include <View.h>
// Support Kit
#include <String.h>
#include "cortex_defs.h"
class BScrollBar;
__BEGIN_CORTEX_NAMESPACE
class ParameterContainerView :
public BView {
public: // *** ctor/dtor
ParameterContainerView(
BRect dataRect,
BView *target);
virtual ~ParameterContainerView();
public: // *** BScrollView impl.
virtual void FrameResized(
float width,
float height);
private: // *** internal operations
void _updateScrollBars();
private: // *** data members
BView* m_target;
BRect m_dataRect;
BRect m_boundsRect;
BScrollBar* m_hScroll;
BScrollBar* m_vScroll;
};
__END_CORTEX_NAMESPACE
#endif /* __ParameterContainerView_H__ */

View File

@ -0,0 +1,356 @@
// ParameterWindow.cpp
#include "ParameterWindow.h"
// ParameterWindow
#include "ParameterContainerView.h"
// Application Kit
#include <Message.h>
#include <Messenger.h>
// Interface Kit
#include <Alert.h>
#include <Menu.h>
#include <MenuBar.h>
#include <MenuItem.h>
#include <Screen.h>
#include <ScrollBar.h>
// Media Kit
#include <MediaRoster.h>
#include <MediaTheme.h>
#include <ParameterWeb.h>
// Storage Kit
#include <FilePanel.h>
#include <Path.h>
// Support Kit
#include <String.h>
__USE_CORTEX_NAMESPACE
#include <Debug.h>
#define D_ALLOC(x) //PRINT (x)
#define D_HOOK(x) //PRINT (x)
#define D_INTERNAL(x) //PRINT (x)
#define D_MESSAGE(x) //PRINT (x)
// -------------------------------------------------------- //
// ctor/dtor
// -------------------------------------------------------- //
ParameterWindow::ParameterWindow(
BPoint position,
live_node_info &nodeInfo,
BMessenger *notifyTarget)
: BWindow(BRect(position, position + BPoint(50.0, 50.0)),
"parameters", B_DOCUMENT_WINDOW,
B_WILL_ACCEPT_FIRST_CLICK | B_ASYNCHRONOUS_CONTROLS),
m_node(nodeInfo.node),
m_parameters(0),
m_notifyTarget(0),
m_zoomed(false),
m_zooming(false) {
D_ALLOC(("ParameterWindow::ParameterWindow()\n"));
// add the nodes name to the title
{
char* title = new char[strlen(nodeInfo.name) + strlen(" parameters") + 1];
sprintf(title, "%s parameters", nodeInfo.name);
SetTitle(title);
delete [] title;
}
// add the menu bar
BMenuBar *menuBar = new BMenuBar(Bounds(), "ParameterWindow MenuBar");
BMenu *menu = new BMenu("Window");
menu->AddItem(new BMenuItem("Start Control Panel",
new BMessage(M_START_CONTROL_PANEL),
'P', B_COMMAND_KEY | B_SHIFT_KEY));
menu->AddSeparatorItem();
menu->AddItem(new BMenuItem("Close",
new BMessage(B_QUIT_REQUESTED),
'W', B_COMMAND_KEY));
menuBar->AddItem(menu);
// future Media Theme selection capabilities go here
menu = new BMenu("Themes");
BMessage *message = new BMessage(M_THEME_SELECTED);
BMediaTheme *theme = BMediaTheme::PreferredTheme();
message->AddInt32("themeID", theme->ID());
BMenuItem *item = new BMenuItem(theme->Name(), message);
item->SetMarked(true);
menu->AddItem(item);
menuBar->AddItem(menu);
AddChild(menuBar);
_updateParameterView();
_init();
// start watching for parameter web changes
BMediaRoster *roster = BMediaRoster::CurrentRoster();
roster->StartWatching(this, nodeInfo.node, B_MEDIA_WILDCARD);
if (notifyTarget) {
m_notifyTarget = new BMessenger(*notifyTarget);
}
}
ParameterWindow::~ParameterWindow() {
D_ALLOC(("ParameterWindow::~ParameterWindow()\n"));
if (m_notifyTarget) {
delete m_notifyTarget;
}
}
// -------------------------------------------------------- //
// BWindow impl
// -------------------------------------------------------- //
void ParameterWindow::FrameResized(
float width,
float height) {
D_HOOK(("ParameterWindow::FrameResized()\n"));
if (!m_zooming) {
m_zoomed = false;
}
else {
m_zooming = false;
}
}
void ParameterWindow::MessageReceived(
BMessage *message) {
D_MESSAGE(("ParameterWindow::MessageReceived()\n"));
switch (message->what) {
case M_START_CONTROL_PANEL: {
D_MESSAGE((" -> M_START_CONTROL_PANEL\n"));
status_t error = _startControlPanel();
if (error) {
BString s = "Could not start control panel";
s << " (" << strerror(error) << ")";
BAlert *alert = new BAlert("", s.String(), "OK", 0, 0,
B_WIDTH_AS_USUAL, B_WARNING_ALERT);
alert->Go(0);
}
bool replace = false;
if ((message->FindBool("replace", &replace) == B_OK)
&& (replace == true)) {
PostMessage(B_QUIT_REQUESTED);
}
break;
}
case M_THEME_SELECTED: {
D_MESSAGE((" -> M_THEME_SELECTED\n"));
int32 themeID;
if (message->FindInt32("themeID", &themeID) != B_OK) {
return;
}
// not yet implemented
break;
}
case B_MEDIA_WEB_CHANGED: {
D_MESSAGE((" -> B_MEDIA_WEB_CHANGED\n"));
_updateParameterView();
_constrainToScreen();
break;
}
default: {
BWindow::MessageReceived(message);
}
}
}
bool ParameterWindow::QuitRequested() {
D_HOOK(("ParameterWindow::QuitRequested()\n"));
// stop watching the MediaRoster
BMediaRoster *roster = BMediaRoster::CurrentRoster();
if (roster) {
roster->StopWatching(this, m_node, B_MEDIA_WILDCARD);
}
// tell the notification target to forget about us
if (m_notifyTarget && m_notifyTarget->IsValid()) {
BMessage message(M_CLOSED);
message.AddInt32("nodeID", m_node.node);
status_t error = m_notifyTarget->SendMessage(&message);
if (error) {
D_HOOK((" -> error sending message (%s) !\n", strerror(error)));
}
}
return true;
}
void ParameterWindow::Zoom(
BPoint origin,
float width,
float height) {
D_HOOK(("ParameterWindow::Zoom()\n"));
m_zooming = true;
BScreen screen(this);
if (!screen.Frame().Contains(Frame())) {
m_zoomed = false;
}
if (!m_zoomed) {
// resize to the ideal size
m_manualSize = Bounds();
ResizeTo(m_idealSize.Width(), m_idealSize.Height());
_constrainToScreen();
m_zoomed = true;
}
else {
// resize to the most recent manual size
ResizeTo(m_manualSize.Width(), m_manualSize.Height());
m_zoomed = false;
}
}
// -------------------------------------------------------- //
// internal operations
// -------------------------------------------------------- //
void ParameterWindow::_init() {
D_INTERNAL(("ParameterWindow::_init()\n"));
// offset to a new position
_constrainToScreen();
m_manualSize = Bounds().OffsetToCopy(0.0, 0.0);
// add the hidden option to close this window when the
// control panel has been started successfully
BMessage *message = new BMessage(M_START_CONTROL_PANEL);
message->AddBool("replace", true);
AddShortcut('P', B_COMMAND_KEY | B_SHIFT_KEY | B_OPTION_KEY,
message);
}
void ParameterWindow::_updateParameterView(
BMediaTheme *theme) {
D_INTERNAL(("ParameterWindow::_updateParameterView()\n"));
// clear the old version
if (m_parameters) {
ParameterContainerView *view = dynamic_cast<ParameterContainerView *>(FindView("ParameterContainerView"));
RemoveChild(view);
delete m_parameters;
m_parameters = 0;
delete view;
}
// fetch ParameterWeb from the MediaRoster
BMediaRoster *roster = BMediaRoster::CurrentRoster();
if (roster) {
BParameterWeb *web;
status_t error = roster->GetParameterWebFor(m_node, &web);
if (!error && (web->CountParameters() || web->CountGroups())) {
// if no theme was specified, use the preferred theme
if (!theme) {
theme = BMediaTheme::PreferredTheme();
}
// acquire the view
m_parameters = BMediaTheme::ViewFor(web, 0, theme);
if (m_parameters) {
BMenuBar *menuBar = KeyMenuBar();
m_idealSize = m_parameters->Bounds();
m_idealSize.right += B_V_SCROLL_BAR_WIDTH;
m_idealSize.bottom += B_H_SCROLL_BAR_HEIGHT;
if (menuBar) {
m_parameters->MoveTo(0.0, menuBar->Bounds().bottom + 1.0);
m_idealSize.bottom += menuBar->Bounds().bottom + 1.0;
}
}
}
}
// limit min size to avoid funny-looking scrollbars
float hMin = B_V_SCROLL_BAR_WIDTH*6, vMin = B_H_SCROLL_BAR_HEIGHT*3;
// limit max size to full extents of the parameter view
float hMax = m_idealSize.Width(), vMax = m_idealSize.Height();
SetSizeLimits(hMin, hMax, vMin, vMax);
// adapt the window to the new dimensions
ResizeTo(m_idealSize.Width(), m_idealSize.Height());
m_zoomed = true;
if (m_parameters) {
BRect paramRect = m_parameters->Bounds();
AddChild(new ParameterContainerView(paramRect, m_parameters));
}
}
void ParameterWindow::_constrainToScreen() {
D_INTERNAL(("ParameterWindow::_constrainToScreen()\n"));
BScreen screen(this);
BRect screenRect = screen.Frame();
BRect windowRect = Frame();
// if the window is outside the screen rect
// move it to the default position
if (!screenRect.Intersects(windowRect)) {
windowRect.OffsetTo(screenRect.LeftTop());
MoveTo(windowRect.LeftTop());
windowRect = Frame();
}
// if the window is larger than the screen rect
// resize it to fit at each side
if (!screenRect.Contains(windowRect)) {
if (windowRect.left < screenRect.left) {
windowRect.left = screenRect.left + 5.0;
MoveTo(windowRect.LeftTop());
windowRect = Frame();
}
if (windowRect.top < screenRect.top) {
windowRect.top = screenRect.top + 5.0;
MoveTo(windowRect.LeftTop());
windowRect = Frame();
}
if (windowRect.right > screenRect.right) {
windowRect.right = screenRect.right - 5.0;
}
if (windowRect.bottom > screenRect.bottom) {
windowRect.bottom = screenRect.bottom - 5.0;
}
ResizeTo(windowRect.Width(), windowRect.Height());
}
}
status_t ParameterWindow::_startControlPanel() {
D_INTERNAL(("ParameterWindow::_startControlPanel()\n"));
// get roster instance
BMediaRoster *roster = BMediaRoster::CurrentRoster();
if (!roster) {
D_INTERNAL((" -> MediaRoster not available\n"));
return B_ERROR;
}
// try to StartControlPanel()
BMessenger messenger;
status_t error = roster->StartControlPanel(m_node, &messenger);
if (error) {
D_INTERNAL((" -> StartControlPanel() failed (%s)\n", strerror(error)));
return error;
}
// notify the notification target, if any
if (m_notifyTarget) {
BMessage message(M_CONTROL_PANEL_STARTED);
message.AddInt32("nodeID", m_node.node);
message.AddMessenger("messenger", messenger);
error = m_notifyTarget->SendMessage(&message);
if (error) {
D_INTERNAL((" -> failed to notify target\n"));
}
}
return B_OK;
}
// END -- ParameterWindow.cpp --

View File

@ -0,0 +1,130 @@
// ParameterWindow.h (Cortex/ParameterWindow)
//
// * PURPOSE
// Window subclass to contain BMediaTheme generated 'parameter
// views' and offers elegant resizing/zooming behaviour.
//
// The ParameterWindow currently listens to the MediaRoster for
// changes of the parameter web, but this should change when the
// provided BMediaTheme becomes more 'intelligent'.
//
// Support for selecting alternate themes is planned, but not
// yet finished (see the 'Themes' menu)
//
// * HISTORY
// c.lenz 24nov99 Begun
// c.lenz 17feb00 Added scrollbar support, migrated the
// basic management functionality to new
// class ParameterWindowManager
//
#ifndef __ParameterWindow_H__
#define __ParameterWindow_H__
// Interface Kit
#include <Window.h>
// Media Kit
#include <MediaNode.h>
class BMessenger;
#include "cortex_defs.h"
__BEGIN_CORTEX_NAMESPACE
class NodeRef;
class ParameterWindow :
public BWindow {
public: // *** messages
enum message_t {
// OUTBOUND
// fields:
// B_INT32_TYPE "nodeID
M_CLOSED = ParameterWindow_message_base,
// OUTBOUND
// fields:
// B_INT32_TYPE "nodeID"
// B_MESSENGER_TYPE "messenger"
M_CONTROL_PANEL_STARTED,
// INBOUND
// fields:
// B_BOOL_TYPE "replace"
M_START_CONTROL_PANEL,
// INBOUND
// fields:
// B_INT32_TYPE "themeID"
M_THEME_SELECTED
};
public: // *** ctor/dtor
ParameterWindow(
BPoint position,
live_node_info &nodeInfo,
BMessenger *notifyTarget = 0);
virtual ~ParameterWindow();
public: // *** BWindow impl
// remember that frame was changed manually
virtual void FrameResized(
float width,
float height);
// closes the window when the node is released
virtual void MessageReceived(
BMessage *message);
// stop watching the MediaRoster, tell the notifyTarget
virtual bool QuitRequested();
// extend basic Zoom() functionality to 'minimize' the
// window when currently at max size
virtual void Zoom(
BPoint origin,
float width,
float height);
private: // *** internal operations
// is called from the ctor for window-positioning
void _init();
// adds or updates the parameter view using the given
// theme
void _updateParameterView(
BMediaTheme *theme = 0);
// resizes the window to fit in the current screen rect
void _constrainToScreen();
// tries to start the nodes control panel through the
// MediaRoster
status_t _startControlPanel();
private: // *** data members
media_node m_node;
BView *m_parameters;
BMessenger *m_notifyTarget;
BRect m_manualSize;
BRect m_idealSize;
bool m_zoomed;
bool m_zooming;
};
__END_CORTEX_NAMESPACE
#endif /* __ParameterWindow_H__ */

View File

@ -0,0 +1,397 @@
// ParameterWindowManager.cpp
#include "ParameterWindowManager.h"
#include "ParameterWindow.h"
// NodeManager
#include "NodeRef.h"
// Application Kit
#include <AppDefs.h>
// Media Kit
#include <MediaRoster.h>
// Support Kit
#include <List.h>
__USE_CORTEX_NAMESPACE
#include <Debug.h>
#define D_ACCESS(x) //PRINT (x)
#define D_ALLOC(x) //PRINT (x)
#define D_INTERNAL(x) //PRINT (x)
#define D_MESSAGE(x) //PRINT (x)
#define D_WINDOW(x) //PRINT (x)
// -------------------------------------------------------- //
// internal types
// -------------------------------------------------------- //
// used to remember the list of ParameterWindows
struct window_map_entry {
public: // *** ctor/dtor
window_map_entry(
const NodeRef *ref,
BWindow *window)
: ref(ref),
window(window)
{ }
public: // *** data members
const NodeRef *ref;
BWindow *window;
};
// used to remember the list of ControlPanels
struct panel_map_entry {
public: // *** ctor/dtor
panel_map_entry(
int32 id,
const BMessenger &messenger)
: id(id),
messenger(messenger)
{ }
public: // *** data members
int32 id;
const BMessenger messenger;
};
// -------------------------------------------------------- //
// static member init
// -------------------------------------------------------- //
const BPoint ParameterWindowManager::M_DEFAULT_OFFSET = BPoint(20.0, 20.0);
const BPoint ParameterWindowManager::M_INIT_POSITION = BPoint(90.0, 90.0);
ParameterWindowManager *ParameterWindowManager::s_instance = 0;
// -------------------------------------------------------- //
// *** ctor/dtor
// -------------------------------------------------------- //
/* hidden */
ParameterWindowManager::ParameterWindowManager()
: BLooper("ParameterWindowManager",
B_NORMAL_PRIORITY),
m_windowList(0),
m_panelList(0),
m_lastWindowPosition(M_INIT_POSITION - M_DEFAULT_OFFSET) {
D_ALLOC(("ParameterWindowManager::ParameterWindowManager()\n"));
m_windowList = new BList();
m_panelList = new BList();
Run();
}
ParameterWindowManager::~ParameterWindowManager() {
D_ALLOC(("ParameterWindowManager::~ParameterWindowManager()\n"));
while (m_windowList->CountItems() > 0) {
window_map_entry *entry = static_cast<window_map_entry *>
(m_windowList->ItemAt(0));
if (entry && entry->window) {
remove_observer(this, entry->ref);
entry->window->Lock();
entry->window->Quit();
}
m_windowList->RemoveItem(reinterpret_cast<void *>(entry));
delete entry;
}
delete m_windowList;
while (m_panelList->CountItems() > 0) {
panel_map_entry *entry = static_cast<panel_map_entry *>
(m_panelList->ItemAt(0));
if (entry && entry->messenger.IsValid()) {
entry->messenger.SendMessage(B_QUIT_REQUESTED);
}
m_panelList->RemoveItem(reinterpret_cast<void *>(entry));
delete entry;
}
delete m_panelList;
s_instance = 0;
}
// -------------------------------------------------------- //
// *** singleton access
// -------------------------------------------------------- //
/*static*/
ParameterWindowManager *ParameterWindowManager::Instance() {
D_ACCESS(("ParameterWindowManager::Instance()\n"));
if (!s_instance) {
D_ACCESS((" -> create instance\n"));
s_instance = new ParameterWindowManager();
}
return s_instance;
}
/* static */
void ParameterWindowManager::shutDown() {
D_WINDOW(("ParameterWindowManager::shutDown()\n"));
if (s_instance) {
s_instance->Lock();
s_instance->Quit();
}
}
// -------------------------------------------------------- //
// *** operations
// -------------------------------------------------------- //
status_t ParameterWindowManager::openWindowFor(
const NodeRef *ref) {
D_WINDOW(("ParameterWindowManager::openWindowFor()\n"));
// make absolutely sure we're locked
if (!IsLocked()) {
debugger("The looper must be locked !");
}
// make sure the ref is valid
if (!ref) {
return B_ERROR;
}
BWindow *window = 0;
if (_findWindowFor(ref->id(), &window)) {
// window for this node already exists, activate it
window->SetWorkspaces(B_CURRENT_WORKSPACE);
window->Activate();
return B_OK;
}
BMessenger messenger(0, this);
live_node_info nodeInfo = ref->nodeInfo();
m_lastWindowPosition += M_DEFAULT_OFFSET;
window = new ParameterWindow(m_lastWindowPosition,
nodeInfo, &messenger);
if (_addWindowFor(ref, window)) {
window->Show();
return B_OK;
}
delete window;
return B_ERROR;
}
status_t ParameterWindowManager::startControlPanelFor(
const NodeRef *ref) {
D_WINDOW(("ParameterWindowManager::startControlPanelFor()\n"));
// make absolutely sure we're locked
if (!IsLocked()) {
debugger("The looper must be locked !");
}
BMediaRoster *roster = BMediaRoster::CurrentRoster();
if (!roster) {
D_WINDOW((" -> MediaRoster not available\n"));
return B_ERROR;
}
BMessenger messenger;
if (_findPanelFor(ref->id(), &messenger)) {
// find out if the messengers target still exists
if (messenger.IsValid()) {
return B_OK;
}
else {
_removePanelFor(ref->id());
}
}
status_t error = roster->StartControlPanel(ref->node(),
&messenger);
if (error) {
D_INTERNAL((" -> StartControlPanel() failed (%s)\n",
strerror(error)));
return error;
}
_addPanelFor(ref->id(), messenger);
return B_OK;
}
// -------------------------------------------------------- //
// *** BLooper impl
// -------------------------------------------------------- //
void ParameterWindowManager::MessageReceived(
BMessage *message) {
D_MESSAGE(("ParameterWindowManager::MessageReceived()\n"));
switch (message->what) {
case ParameterWindow::M_CLOSED: {
D_MESSAGE((" -> ParameterWindow::M_CLOSED\n"));
int32 nodeID;
if (message->FindInt32("nodeID", &nodeID) != B_OK) {
return;
}
_removeWindowFor(nodeID);
break;
}
case ParameterWindow::M_CONTROL_PANEL_STARTED: {
D_MESSAGE((" -> ParameterWindow::M_CONTROL_PANEL_STARTED\n"));
int32 nodeID;
if (message->FindInt32("nodeID", &nodeID) != B_OK) {
return;
}
BMessenger messenger;
if (message->FindMessenger("messenger", &messenger) != B_OK) {
return;
}
_addPanelFor(nodeID, messenger);
break;
}
case NodeRef::M_RELEASED: {
D_MESSAGE((" -> NodeRef::M_RELEASED\n"));
int32 nodeID;
if (message->FindInt32("nodeID", &nodeID) != B_OK) {
return;
}
BWindow *window;
if (_findWindowFor(nodeID, &window)) {
window->Lock();
window->Quit();
_removeWindowFor(nodeID);
}
break;
}
default: {
BLooper::MessageReceived(message);
}
}
}
// -------------------------------------------------------- //
// *** internal operations
// -------------------------------------------------------- //
bool ParameterWindowManager::_addWindowFor(
const NodeRef *ref,
BWindow *window) {
D_INTERNAL(("ParameterWindowManager::_addWindowFor()\n"));
window_map_entry *entry = new window_map_entry(ref,
window);
if (m_windowList->AddItem(reinterpret_cast<void *>(entry))) {
add_observer(this, entry->ref);
return true;
}
return false;
}
bool ParameterWindowManager::_findWindowFor(
int32 id,
BWindow **outWindow) {
D_INTERNAL(("ParameterWindowManager::_findWindowFor()\n"));
for (int32 i = 0; i < m_windowList->CountItems(); i++) {
window_map_entry *entry = static_cast<window_map_entry *>
(m_windowList->ItemAt(i));
if (entry->ref->id() == id) {
*outWindow = entry->window;
return true;
}
}
return false;
}
void ParameterWindowManager::_removeWindowFor(
int32 id) {
D_INTERNAL(("ParameterWindowManager::_removeWindowFor()\n"));
for (int32 i = 0; i < m_windowList->CountItems(); i++) {
window_map_entry *entry = static_cast<window_map_entry *>
(m_windowList->ItemAt(i));
if (entry->ref->id() == id) {
m_windowList->RemoveItem(reinterpret_cast<void *>(entry));
remove_observer(this, entry->ref);
delete entry;
}
}
// try to shutdown
if (m_windowList->CountItems() == 0) {
int32 i = 0;
while (true) {
// take all invalid messengers out of the panel list
panel_map_entry *entry = static_cast<panel_map_entry *>
(m_panelList->ItemAt(i));
if (!entry) {
// end of list
break;
}
if (!entry->messenger.IsValid()) {
// this control panel doesn't exist anymore
m_panelList->RemoveItem(entry);
continue;
}
}
if (m_panelList->CountItems() == 0) {
// neither windows nor panels to manage, go to sleep
PostMessage(B_QUIT_REQUESTED);
}
}
}
bool ParameterWindowManager::_addPanelFor(
int32 id,
const BMessenger &messenger) {
D_INTERNAL(("ParameterWindowManager::_addPanelFor()\n"));
panel_map_entry *entry = new panel_map_entry(id,
messenger);
if (m_panelList->AddItem(reinterpret_cast<void *>(entry))) {
return true;
}
return false;
}
bool ParameterWindowManager::_findPanelFor(
int32 id,
BMessenger *outMessenger) {
D_INTERNAL(("ParameterWindowManager::_findPanelFor()\n"));
for (int32 i = 0; i < m_panelList->CountItems(); i++) {
panel_map_entry *entry = static_cast<panel_map_entry *>
(m_panelList->ItemAt(i));
if (entry->id == id) {
*outMessenger = entry->messenger;
return true;
}
}
return false;
}
void ParameterWindowManager::_removePanelFor(
int32 id) {
D_INTERNAL(("ParameterWindowManager::_removeWindowFor()\n"));
for (int32 i = 0; i < m_panelList->CountItems(); i++) {
panel_map_entry *entry = static_cast<panel_map_entry *>
(m_panelList->ItemAt(i));
if (entry->id == id) {
m_panelList->RemoveItem(reinterpret_cast<void *>(entry));
delete entry;
}
}
}
// END -- ParameterWindowManager.cpp --

View File

@ -0,0 +1,120 @@
// ParameterWindowManager.h
//
// * PURPOSE
// Manages all the ParameterWindows and control panels.
// Will not let you open multiple windows referring to
// the same node, and takes care of quitting them all
// when shut down.
//
// * HISTORY
// c.lenz 17feb2000 Begun
//
#ifndef __ParameterWindowManager_H__
#define __ParameterWindowManager_H__
#include <Looper.h>
#include <Point.h>
class BList;
class BWindow;
#include "cortex_defs.h"
__BEGIN_CORTEX_NAMESPACE
class NodeRef;
class ParameterWindowManager :
public BLooper {
public: // *** constants
// the screen position where the first window should
// be displayed
static const BPoint M_INIT_POSITION;
// horizontal/vertical offset by which subsequent
// parameter windows positions are shifted
static const BPoint M_DEFAULT_OFFSET;
private: // *** ctor/dtor
// hidden ctor; is called only from inside Instance()
ParameterWindowManager();
public:
// quits all registered parameter windows and control
// panels
virtual ~ParameterWindowManager();
public: // *** singleton access
// access to the one and only instance of this class
static ParameterWindowManager *Instance();
// will delete the singleton instance and take down all
// open windows
static void shutDown();
public: // *** operations
// request a ParameterWindow to be openened for the given
// NodeRef; registeres the window
status_t openWindowFor(
const NodeRef *ref);
// request to call StartControlPanel() for the given
// NodeRef; registeres the panels messenger
status_t startControlPanelFor(
const NodeRef *ref);
public: // *** BLooper impl
virtual void MessageReceived(
BMessage *message);
private: // *** internal operations
// ParameterWindow management
bool _addWindowFor(
const NodeRef *ref,
BWindow *window);
bool _findWindowFor(
int32 nodeID,
BWindow **outWindow);
void _removeWindowFor(
int32 nodeID);
// ControlPanel management
bool _addPanelFor(
int32 id,
const BMessenger &messenger);
bool _findPanelFor(
int32 nodeID,
BMessenger *outMessenger);
void _removePanelFor(
int32 nodeID);
private: // *** data members
// a list of window_map_entry objects, ie parameter windows
// identified by the node_id
BList *m_windowList;
// a list of window_map_entry objects, this time for
// node control panels
BList *m_panelList;
// the BPoint at which the last InfoWindow was initially
// opened
BPoint m_lastWindowPosition;
private: // *** static members
// the magic singleton instance
static ParameterWindowManager *s_instance;
};
__END_CORTEX_NAMESPACE
#endif /*__ParameterWindowManager_H__*/

View File

@ -0,0 +1,343 @@
// ExportContext.cpp
// e.moon 30jun99
#include "ExportContext.h"
#include "IPersistent.h"
#include <DataIO.h>
#include <algorithm>
#include <cstdio>
__USE_CORTEX_NAMESPACE
// -------------------------------------------------------- //
// ctor/dtor
// -------------------------------------------------------- //
ExportContext::~ExportContext() {}
ExportContext::ExportContext() :
stream(0),
m_indentLevel(0),
m_indentIncrement(4),
m_attrColumn(30),
m_state(INIT) {}
ExportContext::ExportContext(
BDataIO* _stream) :
stream(_stream),
m_indentLevel(0),
m_indentIncrement(2),
m_attrColumn(30),
m_state(INIT) {
ASSERT(_stream);
}
// -------------------------------------------------------- //
// *** XML formatting helpers
// -------------------------------------------------------- //
// writes a start tag. should only be called from
// IPersistent::xmlExportBegin().
void ExportContext::beginElement(
const char* name) {
ASSERT(name);
if(!m_objectStack.size()) {
reportError("beginElement(): no object being written.\n");
return;
}
if(m_state != WRITE_BEGIN && m_state != WRITE_CONTENT) {
reportError("beginElement(): not allowed.\n");
return;
}
// push tag onto element stack, and link to entry for the current object
m_elementStack.push_back(element_entry());
m_elementStack.back().name = name;
m_objectStack.back().element = m_elementStack.back().name.String();
// write tag
BString out;
out << "\n" << indentString() << '<' << name;
writeString(out);
indentMore();
}
// writes an end tag corresponding to the current element.
// should only be called from IPersistent::xmlExportEnd() or
// xmlExportContent().
void ExportContext::endElement() {
if(!m_objectStack.size()) {
reportError("endElement(): no object being written.\n");
return;
}
ASSERT(m_elementStack.size());
element_entry& entry = m_elementStack.back();
if(m_state != WRITE_END && m_state != WRITE_CONTENT) {
reportError("endElement(): not allowed.\n");
return;
}
indentLess();
BString out;
// write closing tag
if(!entry.hasContent)
out << "/>";
else
out << "\n" << indentString() << "</" << entry.name.String() << ">";
writeString(out);
// pop element off stack
m_elementStack.pop_back();
}
// indicates that content follows (writes the end of the
// current element's start tag.)
void ExportContext::beginContent() {
if(!m_objectStack.size()) {
reportError("beginContent(): no object being written.\n");
return;
}
ASSERT(m_elementStack.size());
element_entry& entry = m_elementStack.back();
if(m_state != WRITE_CONTENT) {
reportError("beginContent(): not allowed.\n");
return;
}
BString out = ">";
writeString(out);
entry.hasContent = true;
}
#define _WRITE_ATTR_BODY(VAL_SPEC) \
if(!m_objectStack.size()) {\
reportError("writeAttr(): no object being written.\n");\
return;\
}\
ASSERT(m_elementStack.size());\
if(m_state != WRITE_ATTRIBUTES &&\
m_state != WRITE_CONTENT) {\
reportError("writeAttr(): not allowed (state mismatch).\n");\
return;\
}\
\
m_elementStack.back().hasAttributes = true;\
\
BString out;\
out << "\n" << indentString() << key;\
_pad_with_spaces(out, key, *this, m_attrColumn) << " = '" << VAL_SPEC << '\'';\
\
writeString(out);
#if B_BEOS_VERSION > B_BEOS_VERSION_4_5
void ExportContext::writeAttr(
const char* key,
int8 value) {_WRITE_ATTR_BODY(value)}
void ExportContext::writeAttr(
const char* key,
uint8 value) {_WRITE_ATTR_BODY(uint32(value))}
void ExportContext::writeAttr(
const char* key,
int16 value) {_WRITE_ATTR_BODY(value)}
void ExportContext::writeAttr(
const char* key,
uint16 value) {_WRITE_ATTR_BODY(uint32(value))}
#endif
void ExportContext::writeAttr(
const char* key,
int32 value) {_WRITE_ATTR_BODY(value)}
void ExportContext::writeAttr(
const char* key,
uint32 value) {_WRITE_ATTR_BODY(value)}
void ExportContext::writeAttr(
const char* key,
int64 value) {_WRITE_ATTR_BODY(value)}
void ExportContext::writeAttr(
const char* key,
uint64 value) {_WRITE_ATTR_BODY(value)}
void ExportContext::writeAttr(
const char* key,
const char* value) {_WRITE_ATTR_BODY(value)}
void ExportContext::writeAttr(
const char* key,
const BString& value) {_WRITE_ATTR_BODY(value)}
void ExportContext::writeAttr(
const char* key,
float value) {_WRITE_ATTR_BODY(value)}
// writes a child object.
// should only be called from IPersistent::xmlExportContent().
// returns B_OK on success, or B_ERROR if an error occurred.
status_t ExportContext::writeObject(
IPersistent* object) {
// * SETUP
ASSERT(object);
if(m_state == ABORT)
return B_ERROR;
state_t origState = m_state;
// write entry to object stack
m_objectStack.push_back(object_entry());
object_entry& entry = m_objectStack.back();
entry.object = object;
// * START TAG
int elements = m_elementStack.size();
m_state = WRITE_BEGIN;
object->xmlExportBegin(*this);
if(m_state == ABORT)
return B_ERROR;
if(!entry.element)
reportError("writeObject(): no start tag for object.\n");
else if(m_elementStack.size() - elements > 1)
reportError("writeObject(): object wrote more than one start tag.\n");
if(m_state == ABORT)
return B_ERROR;
// * ATTRIBUTES
m_state = WRITE_ATTRIBUTES;
object->xmlExportAttributes(*this);
if(m_state == ABORT)
return B_ERROR;
// * CONTENT
m_state = WRITE_CONTENT;
object->xmlExportContent(*this);
if(m_state == ABORT)
return B_ERROR;
// * END
m_state = WRITE_END;
object->xmlExportEnd(*this);
m_state = origState;
// pop object entry
m_objectStack.pop_back();
return (m_state == ABORT) ? B_ERROR : B_OK;
}
// writes an arbitrary string to the stream (calls reportError()
// on failure.)
status_t ExportContext::writeString(
const BString& string) {
return writeString(string.String(), string.Length());
}
status_t ExportContext::writeString(
const char* data,
ssize_t length) {
ssize_t written = stream->Write(data, length);
if(written < 0) {
BString err = "Write error: '";
err << strerror(written) << "'.\n";
reportError(err.String());
return written;
}
else if(written < length) {
BString err = "Write incomplete: '";
err << written << " of " << length << " bytes written.\n";
reportError(err.String());
return B_IO_ERROR;
}
return B_OK;
}
// -------------------------------------------------------- //
// *** indentation helpers
// -------------------------------------------------------- //
const char* ExportContext::indentString() const {
return m_indentString.String();
}
uint16 ExportContext::indentLevel() const {
return m_indentLevel;
}
void ExportContext::indentLess() {
m_indentLevel = (m_indentLevel > m_indentIncrement) ?
m_indentLevel - m_indentIncrement : 0;
m_indentString.SetTo(' ', m_indentLevel);
}
void ExportContext::indentMore() {
m_indentLevel += m_indentIncrement;
m_indentString.SetTo(' ', m_indentLevel);
}
// -------------------------------------------------------- //
// *** error-reporting operations
// -------------------------------------------------------- //
class dump_element { public:
BString& _s;
dump_element(BString& s) : _s(s) {}
void operator()(const ExportContext::element_entry& entry) {
_s << " " << entry.name << '\n';
}
};
// register a fatal error; halts the write process
// as soon as possible.
void ExportContext::reportError(
const char* text) {
m_error << "FATAL ERROR: ";
m_error << text << "\n";
if(m_elementStack.size()) {
_dumpElementStack(m_error);
}
m_state = ABORT;
}
void ExportContext::_dumpElementStack(
BString& out) {
out << "Element stack:\n";
for_each(m_elementStack.begin(), m_elementStack.end(), dump_element(out));
}
// END -- ExportContext.cpp --

View File

@ -0,0 +1,254 @@
// ExportContext.h
// * PURPOSE
// Describe the state of a serialization ('save') operation.
// The 'load' equivalent is ImportContext.
//
// * HISTORY
// e.moon 28jun99 Begun
#ifndef __ExportContext_H__
#define __ExportContext_H__
#include <Debug.h>
#include <String.h>
#include <ostream.h>
#include <list>
#include <utility>
#include "cortex_defs.h"
__BEGIN_CORTEX_NAMESPACE
class IPersistent;
class ExportContext;
// writeAttr() helper
inline BString& _pad_with_spaces(
BString& out,
const char* text,
ExportContext& context,
uint16 column);
class ExportContext {
public: // *** ctor/dtor
virtual ~ExportContext();
ExportContext();
ExportContext(
BDataIO* _stream);
public: // *** public members
// the output stream
BDataIO* stream;
// the element stack
struct element_entry {
element_entry() : hasAttributes(false), hasContent(false) {}
BString name;
bool hasAttributes;
bool hasContent;
};
typedef list<element_entry> element_list;
element_list m_elementStack;
public: // *** XML formatting helpers
// writes a start tag. should be called from
// IPersistent::xmlExportBegin()
// (or xmlExportContent(), if you're writing nested elements)
void beginElement(
const char* name);
// writes an end tag corresponding to the current element.
// should only be called from IPersistent::xmlExportEnd() or
// xmlExportContent().
void endElement();
// indicates that content follows (writes the end of the
// current element's start tag.)
void beginContent();
// // writes an attribute.
// // should only be called from IPersistent::xmlExportAttributes().
// template <class T>
// void writeAttr(
// const char* key,
// T value) {
//
// if(!m_objectStack.size()) {
// reportError("writeAttr(): no object being written.\n");
// return;
// }
// ASSERT(m_elementStack.size());
// if(m_state != WRITE_ATTRIBUTES &&
// m_state != WRITE_CONTENT) {
// reportError("writeAttr(): not allowed (state mismatch).\n");
// return;
// }
//
// m_elementStack.back().hasAttributes = true;
//
// BString out;
// out << "\n" << indentString() << key;
// _pad_with_spaces(out, key, *this, m_attrColumn) << " = '" << value << '\'';
//
// writeString(out);
// }
// [e.moon 22dec99]
// non-template forms of writeAttr()
#if B_BEOS_VERSION > B_BEOS_VERSION_4_5
void writeAttr(
const char* key,
int8 value);
void writeAttr(
const char* key,
uint8 value);
void writeAttr(
const char* key,
int16 value);
void writeAttr(
const char* key,
uint16 value);
#endif
void writeAttr(
const char* key,
int32 value);
void writeAttr(
const char* key,
uint32 value);
void writeAttr(
const char* key,
int64 value);
void writeAttr(
const char* key,
uint64 value);
void writeAttr(
const char* key,
const char* value);
void writeAttr(
const char* key,
const BString& value);
void writeAttr(
const char* key,
float value);
// writes a child object.
// should only be called from IPersistent::xmlExportContent().
// returns B_OK on success, or B_ERROR if an error occurred.
status_t writeObject(
IPersistent* object);
// writes an arbitrary string to the stream (calls reportError()
// on failure.)
status_t writeString(
const BString& string);
status_t writeString(
const char* data,
ssize_t length);
public: // *** indentation helpers
// return a string padded with spaces to the current
// indent level
const char* indentString() const;
// return the current indent level
uint16 indentLevel() const;
// decrease the indent level
void indentLess();
// increase the indent level
void indentMore();
// +++++ extra formatting controls needed [e.moon 1dec99]
// * attrColumn access
// * single vs. multi-line element formatting
public: // *** error operations
// register a fatal error; halts the write process
// as soon as possible.
void reportError(
const char* text);
// fetch error text
const char* errorText() const { return m_error.String(); }
private: // members
// * Indentation/formatting
uint16 m_indentLevel;
uint16 m_indentIncrement;
uint16 m_attrColumn;
BString m_indentString;
// * State
enum state_t {
INIT,
WRITE_BEGIN,
WRITE_ATTRIBUTES,
WRITE_CONTENT,
WRITE_END,
ABORT
};
state_t m_state;
BString m_error;
// object stack
struct object_entry {
object_entry() : element(0), object(0) {}
const char* element;
IPersistent* object;
};
typedef list<object_entry> object_list;
object_list m_objectStack;
private:
void _dumpElementStack(
BString& out);
};
// ExportContext::writeAttr() helper
inline BString& _pad_with_spaces(
BString& out,
const char* text,
ExportContext& context,
uint16 column) {
int16 spaces = column - (strlen(text) + context.indentLevel());
if(spaces < 0) spaces = 0;
while(spaces--) out << ' ';
return out;
}
__END_CORTEX_NAMESPACE
#endif /*__ExportContext_H__*/

View File

@ -0,0 +1,167 @@
// IPersistant.h
// * PURPOSE
// Interface to be implemented by objects that want to
// be persistent (loadable/savable) via XML.
//
// * TO DO +++++ IN PROGRESS 8jul99
// - Make the export API friendlier: classes shouldn't have to
// know how to format XML, and it should be easy to extend
// the serialization capabilities in a subclass. [8jul99]
// * should this stuff be exposed via ExportContext methods?
//
// - FBC stuffing? [29jun99]
//
// * HISTORY
// e.moon 29jun99 Reworking; merging with the interface
// formerly known as Condenser.
// e.moon 28jun99 Begun
#ifndef __IPersistent_H__
#define __IPersistent_H__
#include "ImportContext.h"
#include "ExportContext.h"
#include <ostream.h>
#include "cortex_defs.h"
__BEGIN_CORTEX_NAMESPACE
class IPersistent {
public:
// empty virtual dtor
virtual ~IPersistent() {}
public: // *** REQUIRED INTERFACE
// 8jul99 export rework
// // EXPORT:
// // write an XML representation of this object (including
// // any child objects) to the given stream. use the
// // provided context object to format the output nicely.
//
// virtual void xmlExport(
// ostream& stream,
// ExportContext& context) const =0;
// EXPORT:
// implement this method to write a start tag via
// context.startElement(). You can also write comments or
// processing instructions directly to the stream.
virtual void xmlExportBegin(
ExportContext& context) const=0;
// EXPORT:
// implement this method to write all the attributes needed
// to represent your object, via context.writeAttribute().
// (If subclassing an IPersistent implementation, don't forget
// to call up to its version of this method.)
virtual void xmlExportAttributes(
ExportContext& context) const=0;
// EXPORT: optional
// implement this method to write any child objects, using
// context.writeObject(). You can also write text content
// directly to the stream.
// (If subclassing an IPersistent implementation, don't forget
// to call up to its version of this method.)
virtual void xmlExportContent(
ExportContext& context) const { TOUCH(context); }
// EXPORT:
// implement this method to write an end tag via
// context.endElement().
virtual void xmlExportEnd(
ExportContext& context) const=0;
// IMPORT:
// called when the start tag of the element corresponding to
// this object is encountered, immediately after this object
// is constructed. no action is required.
//
// context.element() will return the element name that produced
// this object.
virtual void xmlImportBegin(
ImportContext& context) =0;
// IMPORT:
// called for each attribute/value pair found in
// the element corresponding to this object.
virtual void xmlImportAttribute(
const char* key,
const char* value,
ImportContext& context) =0;
// IMPORT:
// called when character data is encountered for the
// element corresponding to this object. data is not
// 0-terminated; this method may be called several times
// (if, for example, the character data is broken up
// by child elements.)
virtual void xmlImportContent(
const char* data,
uint32 length,
ImportContext& context) =0;
// IMPORT:
// called when an object has been successfully
// constructed 'beneath' this one.
//
// context.element() will return the element name corresponding
// to the child object.
virtual void xmlImportChild(
IPersistent* child,
ImportContext& context) =0;
// IMPORT:
// called when close tag is encountered for the element
// corresponding to this object. a good place to do
// validation.
//
// context.element() will return the element name that produced
// this object.
virtual void xmlImportComplete(
ImportContext& context) =0;
public: // *** OPTIONAL CHILD-IMPORT INTERFACE
// These methods allow an IPersistent object
// to directly import nested elements: handy for
// condensing more complicated document structures
// into a single object (see MediaFormatIO for an
// example.)
virtual void xmlImportChildBegin(
const char* name,
ImportContext& context) {
TOUCH(name);
context.reportWarning("Nested element not supported.");
}
virtual void xmlImportChildAttribute(
const char* key,
const char* value,
ImportContext& context) {TOUCH(key); TOUCH(value); TOUCH(context);}
virtual void xmlImportChildContent(
const char* data,
uint32 length,
ImportContext& context) {TOUCH(data); TOUCH(length); TOUCH(context);}
virtual void xmlImportChildComplete(
const char* name,
ImportContext& context) {TOUCH(name); TOUCH(context);}
};
__END_CORTEX_NAMESPACE
#endif /*__IPersistent_H__*/

View File

@ -0,0 +1,30 @@
// IStateArchivable.h
// * PURPOSE
// Similar to BArchivable, but provides for archiving of
// a particular object's state, not the object itself.
// This mechanism doesn't instantiate objects.
//
// * HISTORY
// e.moon 27nov99 Begun
#ifndef __IStateArchivable_H__
#define __IStateArchivable_H__
#include "cortex_defs.h"
__BEGIN_CORTEX_NAMESPACE
class IStateArchivable {
public:
// empty virtual dtor
virtual ~IStateArchivable() {}
public: // *** INTERFACE
virtual status_t importState(
const BMessage* archive) =0;
virtual status_t exportState(
BMessage* archive) const =0;
};
__END_CORTEX_NAMESPACE
#endif /*__IStateArchivable_H__*/

View File

@ -0,0 +1,104 @@
// ImportContext.cpp
// e.moon 1jul99
#include "ImportContext.h"
#include "xmlparse.h"
__USE_CORTEX_NAMESPACE
// -------------------------------------------------------- //
// ctor/dtor
// -------------------------------------------------------- //
ImportContext::~ImportContext() {}
ImportContext::ImportContext(list<BString>& errors) :
m_state(PARSING),
m_errors(errors),
m_pParser(0) {}
// -------------------------------------------------------- //
// accessors
// -------------------------------------------------------- //
// fetch the current element (tag)
// (returns 0 if the stack is empty)
const char* ImportContext::element() const {
return (m_elementStack.size()) ?
m_elementStack.back().String() :
0;
}
const char* ImportContext::parentElement() const {
if(m_elementStack.size() < 2)
return 0;
list<BString>::const_reverse_iterator it = m_elementStack.rbegin();
++it;
return (*it).String();
}
list<BString>& ImportContext::errors() const {
return m_errors;
}
const ImportContext::state_t ImportContext::state() const {
return m_state;
}
// -------------------------------------------------------- //
// error-reporting operations
// -------------------------------------------------------- //
// register a warning to be returned once the deserialization
// process is complete.
void ImportContext::reportWarning(
const char* pText) {
XML_Parser p = (XML_Parser)m_pParser;
BString err = "Warning: ";
err << pText;
if(p) {
err << "\n (line " <<
(uint32)XML_GetCurrentLineNumber(p) << ", column " <<
(uint32)XML_GetCurrentColumnNumber(p) << ", element '" <<
(element() ? element() : "(none)") << "')\n";
} else
err << "\n";
m_errors.push_back(err);
}
// register a fatal error; halts the deserialization process
// as soon as possible.
void ImportContext::reportError(
const char* pText) {
XML_Parser p = (XML_Parser)m_pParser;
BString err = "FATAL ERROR: ";
err << pText;
if(p) {
err << "\n (line " <<
(uint32)XML_GetCurrentLineNumber(p) << ", column " <<
(uint32)XML_GetCurrentColumnNumber(p) << ", element '" <<
(element() ? element() : "(none)") << "')\n";
} else
err << "\n";
m_errors.push_back(err);
m_state = ABORT;
}
// -------------------------------------------------------- //
// internal operations
// -------------------------------------------------------- //
void ImportContext::reset() {
m_state = PARSING;
m_elementStack.clear();
// +++++ potential for memory leaks; reset() is currently
// only to be called after an identify cycle, during
// which no objects are created anyway, but this still
// gives me the shivers...
m_objectStack.clear();
}
// END -- ImportContext.cpp --

View File

@ -0,0 +1,76 @@
// ImportContext.h
// * PURPOSE
// Describe the state of a deserialization ('load') operation.
// The 'save' equivalent is ExportContext.
//
// * HISTORY
// e.moon 29jun99 Begun
#ifndef __ImportContext_H__
#define __ImportContext_H__
#include <list>
#include <utility>
#include <String.h>
#include "cortex_defs.h"
__BEGIN_CORTEX_NAMESPACE
class IPersistent;
class ImportContext {
friend class Importer;
public: // *** types
enum state_t {
PARSING,
COMPLETE,
ABORT
};
public: // *** ctor/dtor
virtual ~ImportContext();
ImportContext(
list<BString>& errors);
public: // *** accessors
// fetch the current element (tag)
// (returns 0 if the stack is empty)
const char* element() const;
// fetch the current element's parent
// (returns 0 if the stack is empty or the current element is top-level)
const char* parentElement() const;
list<BString>& errors() const;
const state_t state() const;
public: // *** error-reporting operations
// register a warning to be returned once the deserialization
// process is complete.
void reportWarning(
const char* text);
// register a fatal error; halts the deserialization process
// as soon as possible.
void reportError(
const char* text);
protected: // *** internal operations
void reset();
private: // *** members
state_t m_state;
list<BString>& m_errors;
list<BString> m_elementStack;
typedef pair<const char*, IPersistent*> object_entry;
list<object_entry> m_objectStack;
void* m_pParser;
};
__END_CORTEX_NAMESPACE
#endif /*__ImportContext_H__*/

View File

@ -0,0 +1,460 @@
// Importer.cpp
// e.moon 28jun99
#include "Importer.h"
#include <stdexcept>
#include <Autolock.h>
#include <Debug.h>
__USE_CORTEX_NAMESPACE
// -------------------------------------------------------- //
// expat hooks
// -------------------------------------------------------- //
void _oc_handle_start(
void* pUser,
const XML_Char* pName,
const XML_Char** ppAtts) {
((Importer*)pUser)->xmlElementStart(pName, ppAtts);
}
void _oc_handle_end(
void* pUser,
const XML_Char* pName) {
((Importer*)pUser)->xmlElementEnd(pName);
}
void _oc_handle_pi(
void* pUser,
const XML_Char* pTarget,
const XML_Char* pData) {
((Importer*)pUser)->xmlProcessingInstruction(pTarget, pData);
}
void _oc_handle_char(
void* pUser,
const XML_Char* pData,
int length) {
((Importer*)pUser)->xmlCharacterData(pData, length);
}
void _oc_handle_default(
void* pUser,
const XML_Char* pData,
int length) {
((Importer*)pUser)->xmlDefaultData(pData, length);
}
// -------------------------------------------------------- //
// ctor/dtor
// -------------------------------------------------------- //
Importer::~Importer() {
// clean up
freeParser();
delete m_context;
}
Importer::Importer(
list<BString>& errors) :
m_parser(0),
m_docType(0),
m_identify(false),
m_context(new ImportContext(errors)),
m_rootObject(0) {
initParser();
}
Importer::Importer(
ImportContext* context) :
m_parser(0),
m_docType(0),
m_identify(false),
m_context(context),
m_rootObject(0) {
ASSERT(m_context);
initParser();
}
Importer::Importer(
list<BString>& errors,
IPersistent* rootObject,
XML::DocumentType* docType) :
m_parser(0),
m_docType(docType),
m_identify(false),
m_context(new ImportContext(errors)),
m_rootObject(rootObject) {
ASSERT(rootObject);
ASSERT(docType);
initParser();
}
Importer::Importer(
ImportContext* context,
IPersistent* rootObject,
XML::DocumentType* docType) :
m_parser(0),
m_docType(docType),
m_identify(false),
m_context(context),
m_rootObject(rootObject) {
ASSERT(m_context);
ASSERT(rootObject);
ASSERT(docType);
initParser();
}
// -------------------------------------------------------- //
// accessors
// -------------------------------------------------------- //
// the import context
const ImportContext& Importer::context() const {
return *m_context;
}
// matched (or provided) document type
XML::DocumentType* Importer::docType() const {
return m_docType;
}
// completed object (available if
// context().state() == ImportContext::COMPLETE, or
// if a root object was provided to the ctor)
IPersistent* Importer::target() const {
return m_rootObject;
}
// -------------------------------------------------------- //
// operations
// -------------------------------------------------------- //
// put the importer into 'identify mode'
// (disengaged once the first element is encountered)
void Importer::setIdentifyMode() {
reset();
m_docType = 0;
m_identify = true;
}
void Importer::reset() {
// doesn't forget document type from identify cycle!
m_identify = false;
m_context->reset();
m_rootObject = 0;
}
// handle a buffer; return false if an error occurs
bool Importer::parseBuffer(
const char* pBuffer,
uint32 length,
bool last) {
ASSERT(m_parser);
int err = XML_Parse(m_parser, pBuffer, length, last);
if(!err) {
BString str = "Parse Error: ";
str << XML_ErrorString(XML_GetErrorCode(m_parser));
m_context->reportError(str.String());
return false;
} else
return true;
}
// -------------------------------------------------------- //
// internal operations
// -------------------------------------------------------- //
// create & initialize parser
void Importer::initParser() {
ASSERT(!m_parser);
m_parser = XML_ParserCreate(0);
m_context->m_pParser = m_parser;
XML_SetElementHandler(
m_parser,
&_oc_handle_start,
&_oc_handle_end);
XML_SetProcessingInstructionHandler(
m_parser,
&_oc_handle_pi);
XML_SetCharacterDataHandler(
m_parser,
&_oc_handle_char);
XML_SetDefaultHandlerExpand(
m_parser,
&_oc_handle_default);
XML_SetUserData(
m_parser,
(void*)this);
}
// clean up the parser
void Importer::freeParser() {
ASSERT(m_parser);
XML_ParserFree(m_parser);
m_parser = 0;
}
// -------------------------------------------------------- //
// XML parser event hooks
// -------------------------------------------------------- //
void Importer::xmlElementStart(
const char* pName,
const char** ppAttributes) {
if(m_context->m_state != ImportContext::PARSING)
return;
IPersistent* target = 0;
if(!m_context->m_elementStack.size()) {
// this is the first element; identify or verify document type
if(m_rootObject) {
// test against expected document type
ASSERT(m_docType);
if(m_docType->rootElement != pName) {
BString err("Unexpected document element (should be <");
err << m_docType->rootElement << "/>";
m_context->reportError(err.String());
return;
}
// target the provided root object
target = m_rootObject;
}
else {
// look up doc type
BAutolock _l(XML::s_docTypeLock);
XML::doc_type_map::iterator it = XML::s_docTypeMap.find(
BString(pName));
if(it != XML::s_docTypeMap.end())
m_docType = (*it).second;
else {
// whoops, don't know how to handle this element:
BString err("No document type registered for element '");
err << pName << "'.";
m_context->reportError(err.String());
return;
}
if(m_identify) {
// end of identify cycle
m_context->m_state = ImportContext::COMPLETE;
return;
}
}
}
// at this point, there'd better be a valid document type
ASSERT(m_docType);
// push element name onto the stack
m_context->m_elementStack.push_back(pName);
// try to create an object for this element if necessary
if(!target)
target = m_docType->objectFor(pName);
if(target) {
// call 'begin import' hook
m_context->m_objectStack.push_back(
make_pair(m_context->element(), target));
target->xmlImportBegin(*m_context);
// error? bail
if(m_context->state() != ImportContext::PARSING)
return;
// walk attributes
while(*ppAttributes) {
target->xmlImportAttribute(
ppAttributes[0],
ppAttributes[1],
*m_context);
// error? bail
if(m_context->state() != ImportContext::PARSING)
return;
ppAttributes += 2;
}
} else {
// no object directly maps to this element; hand to
// the current focus object
ASSERT(m_context->m_objectStack.size());
IPersistent* curObject = m_context->m_objectStack.back().second;
ASSERT(curObject);
curObject->xmlImportChildBegin(
pName,
*m_context);
// error? bail
if(m_context->state() != ImportContext::PARSING)
return;
// walk attributes
while(*ppAttributes) {
curObject->xmlImportChildAttribute(
ppAttributes[0],
ppAttributes[1],
*m_context);
// error? bail
if(m_context->state() != ImportContext::PARSING)
return;
ppAttributes += 2;
}
}
}
void Importer::xmlElementEnd(
const char* pName) {
if(m_context->m_state != ImportContext::PARSING)
return;
ASSERT(m_docType);
// PRINT(("Importer::xmlElementEnd(): %s\n", pName));
// compare name to element on top of stack
if(!m_context->m_elementStack.size() ||
m_context->m_elementStack.back() != pName) {
m_context->reportError("Mismatched end tag.");
return;
}
// see if it matches the topmost object
IPersistent* pObject = 0;
if(!m_context->m_objectStack.size()) {
m_context->reportError("No object being constructed.");
return;
}
if(m_context->m_objectStack.back().first == m_context->element()) {
// matched; pop it
pObject = m_context->m_objectStack.back().second;
m_context->m_objectStack.pop_back();
}
if(pObject) {
// notify object that import is complete
pObject->xmlImportComplete(
*m_context);
// error? bail
if(m_context->state() != ImportContext::PARSING)
return;
if(m_context->m_objectStack.size()) {
// hand the newly-constructed child to its parent
m_context->m_objectStack.back().second->xmlImportChild(
pObject,
*m_context);
} else {
// done
ASSERT(m_context->m_elementStack.size() == 1);
m_context->m_state = ImportContext::COMPLETE;
if(m_rootObject) {
ASSERT(m_rootObject == pObject);
} else
m_rootObject = pObject;
}
}
else {
// notify current topmost object
ASSERT(m_context->m_objectStack.size());
IPersistent* curObject = m_context->m_objectStack.back().second;
ASSERT(curObject);
curObject->xmlImportChildComplete(
pName,
*m_context);
}
// remove entry from element stack
m_context->m_elementStack.pop_back();
ASSERT(m_context->m_objectStack.size() <= m_context->m_elementStack.size());
}
void Importer::xmlProcessingInstruction(
const char* pTarget,
const char* pData) {
if(m_context->m_state != ImportContext::PARSING)
return;
// PRINT(("Importer::xmlProcessingInstruction(): %s, %s\n",
// pTarget, pData));
}
// not 0-terminated
void Importer::xmlCharacterData(
const char* pData,
int32 length) {
if(m_context->m_state != ImportContext::PARSING)
return;
// see if the current element matches the topmost object
IPersistent* pObject = 0;
if(!m_context->m_objectStack.size()) {
m_context->reportError("No object being constructed.");
return;
}
pObject = m_context->m_objectStack.back().second;
if(m_context->m_objectStack.back().first == m_context->element()) {
pObject->xmlImportContent(
pData,
length,
*m_context);
}
else {
pObject->xmlImportChildContent(
pData,
length,
*m_context);
}
}
// not 0-terminated
void Importer::xmlDefaultData(
const char* pData,
int32 length) {
if(m_context->m_state != ImportContext::PARSING)
return;
// PRINT(("Importer::xmlDefaultData()\n"));
}
// END -- Importer.cpp --

View File

@ -0,0 +1,131 @@
// Importer.h
//
// * PURPOSE
// Given a stream of XML parser events, produce the object[s]
// represented by the markup.
//
// * HISTORY
// e.moon 30jun99 Moved actual object-building responsibility
// to IPersistent; this class is now internal
// to Cortex::XML.
// e.moon 28jun99 Begun. [was 'Importer']
#ifndef __Importer_H__
#define __Importer_H__
#include <list>
#include <String.h>
#include "ImportContext.h"
#include "XML.h"
#include "xmlparse.h"
#include "cortex_defs.h"
__BEGIN_CORTEX_NAMESPACE
class Importer {
public: // *** ctor/dtor
virtual ~Importer();
// constructs a format-guessing Importer (uses the
// DocumentType registry)
Importer(
list<BString>& errors);
// the Importer takes ownership of the given context!
Importer(
ImportContext* context);
// constructs a manual Importer; the given root
// object is populated
Importer(
list<BString>& errors,
IPersistent* rootObject,
XML::DocumentType* docType);
// the Importer takes ownership of the given context!
Importer(
ImportContext* context,
IPersistent* rootObject,
XML::DocumentType* docType);
public: // *** accessors
// the import context
const ImportContext& context() const;
// matched document type
XML::DocumentType* docType() const;
// completed object (available if
// context().state() == ImportContext::COMPLETE, or
// if a root object was provided to the ctor)
IPersistent* target() const;
public: // *** operations
// put the importer into 'identify mode'
// (disengaged once the first element is encountered)
void setIdentifyMode();
// prepare to read the document after an identify cycle
void reset();
// handle a buffer; return false if an error occurs
bool parseBuffer(
const char* buffer,
uint32 length,
bool last);
public: // *** internal operations
// create & initialize parser
void initParser();
// clean up the parser
void freeParser();
public: // *** XML parser event hooks
virtual void xmlElementStart(
const char* name,
const char** attributes);
virtual void xmlElementEnd(
const char* name);
virtual void xmlProcessingInstruction(
const char* target,
const char* data);
// not 0-terminated
virtual void xmlCharacterData(
const char* data,
int32 length);
// not 0-terminated
virtual void xmlDefaultData(
const char* data,
int32 length);
private: // *** implementation
XML_Parser m_parser;
XML::DocumentType* m_docType;
// if true, the importer is being used to identify the
// document type -- it should halt as soon as the first
// element is encountered.
bool m_identify;
ImportContext* const m_context;
// the constructed object: if no rootObject was provided
// in the ctor, this is only filled in once the document
// end tag has been encountered.
IPersistent* m_rootObject;
};
__END_CORTEX_NAMESPACE
#endif /*__Importer_H__*/

View File

@ -0,0 +1,75 @@
// StringContent.cpp
#include "StringContent.h"
#include "ImportContext.h"
#include <cctype>
__USE_CORTEX_NAMESPACE
// -------------------------------------------------------- //
// EXPORT [not implemented]
// -------------------------------------------------------- //
void StringContent::xmlExportBegin(
ExportContext& context) const {
context.reportError("StringContent: no export");
}
void StringContent::xmlExportAttributes(
ExportContext& context) const {
context.reportError("StringContent: no export");
}
void StringContent::xmlExportContent(
ExportContext& context) const {
context.reportError("StringContent: no export");
}
void StringContent::xmlExportEnd(
ExportContext& context) const {
context.reportError("StringContent: no export");
}
// -------------------------------------------------------- //
// IMPORT
// -------------------------------------------------------- //
void StringContent::xmlImportBegin(
ImportContext& context) {}
void StringContent::xmlImportAttribute(
const char* key,
const char* value,
ImportContext& context) {}
void StringContent::xmlImportContent(
const char* data,
uint32 length,
ImportContext& context) {
content.Append(data, length);
}
void StringContent::xmlImportChild(
IPersistent* child,
ImportContext& context) {
context.reportError("StringContent: child not expected");
}
void StringContent::xmlImportComplete(
ImportContext& context) {
// chomp leading/trailing whitespace
if(content.Length() == 0)
return;
int32 last = 0;
for(; last < content.Length() && isspace(content[last]); ++last) {}
if(last > 0)
content.Remove(0, last);
last = content.Length() - 1;
int32 from = last;
for(; from > 0 && isspace(content[from]); --from) {}
if(from < last)
content.Remove(from+1, last-from);
}
// END -- StringContent.cpp --

View File

@ -0,0 +1,73 @@
// StringContent.h
// * PURPOSE
// Implements IPersistent to store element content in
// a BString and automatically strip leading/trailing
// whitespace. Doesn't handle child elements; export
// is not implemented (triggers an error).
//
// * HISTORY
// e.moon 7dec99 Begun
#ifndef __StringContent_H__
#define __StringContent_H__
#include <MediaDefs.h>
#include "XML.h"
#include "cortex_defs.h"
__BEGIN_CORTEX_NAMESPACE
class StringContent :
public IPersistent {
public: // content access
BString content;
public: // *** dtor, default ctors
virtual ~StringContent() {}
StringContent() {}
StringContent(
const char* c) : content(c) {}
public: // *** IPersistent
// EXPORT
virtual void xmlExportBegin(
ExportContext& context) const;
virtual void xmlExportAttributes(
ExportContext& context) const;
virtual void xmlExportContent(
ExportContext& context) const;
virtual void xmlExportEnd(
ExportContext& context) const;
// IMPORT
virtual void xmlImportBegin(
ImportContext& context);
virtual void xmlImportAttribute(
const char* key,
const char* value,
ImportContext& context);
virtual void xmlImportContent(
const char* data,
uint32 length,
ImportContext& context);
virtual void xmlImportChild(
IPersistent* child,
ImportContext& context);
virtual void xmlImportComplete(
ImportContext& context);
};
__END_CORTEX_NAMESPACE
#endif /*__StringContent_H__ */

View File

@ -0,0 +1,187 @@
// FlatMessageIO.cpp
// e.moon 6jul99
#include "FlatMessageIO.h"
//#include "xml_export_utils.h"
#include "ExportContext.h"
#include <Debug.h>
// base64 encoding tools
#include <E-mail.h>
#include <cstdlib>
#include <cstring>
__USE_CORTEX_NAMESPACE
// -------------------------------------------------------- //
// *** constants
// -------------------------------------------------------- //
const char* const FlatMessageIO::s_element = "flat-BMessage";
// -------------------------------------------------------- //
// *** ctor/dtor/accessor
// -------------------------------------------------------- //
FlatMessageIO::~FlatMessageIO() {
if(m_ownMessage && m_message)
delete m_message;
}
FlatMessageIO::FlatMessageIO() :
m_ownMessage(true),
m_message(0) {}
FlatMessageIO::FlatMessageIO(const BMessage* message) :
m_ownMessage(false),
m_message(const_cast<BMessage*>(message)) {}
void FlatMessageIO::setMessage(BMessage* message) {
if(m_ownMessage && m_message)
delete m_message;
m_ownMessage = false;
m_message = message;
}
// -------------------------------------------------------- //
// *** static setup method
// -------------------------------------------------------- //
// call this method to install hooks for the tags needed by
// FlatMessageIO into the given document type
/*static*/
void FlatMessageIO::AddTo(XML::DocumentType* pDocType) {
pDocType->addMapping(new Mapping<FlatMessageIO>(s_element));
}
// -------------------------------------------------------- //
// *** IPersistent impl.
// -------------------------------------------------------- //
void FlatMessageIO::xmlExportBegin(
ExportContext& context) const {
context.beginElement(s_element);
}
void FlatMessageIO::xmlExportAttributes(
ExportContext& context) const {
context.writeAttr("encoding", "base64");
}
void FlatMessageIO::xmlExportContent(
ExportContext& context) const {
context.beginContent();
// convert message to base64
ASSERT(m_message);
ssize_t flatSize = m_message->FlattenedSize();
ASSERT(flatSize);
char* flatData = new char[flatSize];
status_t err = m_message->Flatten(flatData, flatSize);
ASSERT(err == B_OK);
// make plenty of room for encoded content (encode_base64 adds newlines)
ssize_t base64Size = ((flatSize * 3) / 2);
char* base64Data = new char[base64Size];
ssize_t base64Used = encode_base64(base64Data, flatData, flatSize);
base64Data[base64Used] = '\0';
// write the data
const char* pos = base64Data;
while(*pos) {
ssize_t chunk = 0;
const char* nextBreak = strchr(pos, '\n');
if(!nextBreak)
chunk = strlen(pos);
else
chunk = nextBreak - pos;
context.writeString(context.indentString());
context.writeString(pos, chunk);
context.writeString("\n");
pos += chunk;
if(*pos == '\n')
++pos;
}
// clean up
delete [] flatData;
delete [] base64Data;
}
void FlatMessageIO::xmlExportEnd(
ExportContext& context) const {
context.endElement();
}
// -------------------------------------------------------- //
void FlatMessageIO::xmlImportBegin(
ImportContext& context) {
m_base64Data = "";
}
void FlatMessageIO::xmlImportAttribute(
const char* key,
const char* value,
ImportContext& context) {
if(!strcmp(key, "encoding")) {
if(strcmp(value, "base64") != 0)
context.reportError("Unexpected value of 'encoding'.");
}
}
void FlatMessageIO::xmlImportContent(
const char* data,
uint32 length,
ImportContext& context) {
m_base64Data.Append(data, length);
}
void FlatMessageIO::xmlImportChild(
IPersistent* child,
ImportContext& context) {
delete child;
context.reportError("Unexpected child object.");
}
void FlatMessageIO::xmlImportComplete(
ImportContext& context) {
if(m_ownMessage && m_message)
delete m_message;
// decode the message
ssize_t decodedSize = m_base64Data.Length();
char* decodedData = new char[decodedSize];
decodedSize = decode_base64(
decodedData, const_cast<char*>(m_base64Data.String()),
m_base64Data.Length(), false);
m_message = new BMessage();
m_ownMessage = true;
status_t err = m_message->Unflatten(decodedData);
if(err < B_OK) {
// decode failed; report error & clean up
BString error = "Unflatten(): ";
error << strerror(err);
context.reportError(error.String());
delete m_message;
m_message = 0;
}
m_base64Data = "";
delete [] decodedData;
}
// END -- FlatMessageIO.cpp --

View File

@ -0,0 +1,114 @@
// FlatMessageIO.h
// * PURPOSE
// Efficient export/import of BMessages to and from
// XML using the Cortex persistence library.
// Messages are stored in flattened form.
// * HISTORY
// e.moon 6jul99 Begun.
//
// Example:
//
// <flat-BMessage
// encoding = 'base64'>
// nKJNFBlkn3lknbxlkfnbLKN/lknlknlDSLKn3lkn3l2k35234ljk234
// lkdsg23823nlknsdlkbNDSLKBNlkn3lk23n4kl23n423lknLKENL+==
// </flat-BMessage>
#ifndef __FlatMessageIO_H__
#define __FlatMessageIO_H__
#include <Message.h>
#include <String.h>
#include "XML.h"
#include "cortex_defs.h"
__BEGIN_CORTEX_NAMESPACE
class FlatMessageIO :
public IPersistent {
public: // *** ctor/dtor/accessor
virtual ~FlatMessageIO();
FlatMessageIO();
// When given a message to export, this object does NOT take
// responsibility for deleting it. It will, however, handle
// deletion of an imported BMessage.
FlatMessageIO(const BMessage* message);
void setMessage(BMessage* message);
// Returns 0 if no message has been set, and if no message has
// been imported.
const BMessage* message() const { return m_message; }
// Returns true if the message will be automatically deleted.
bool ownsMessage() const { return m_ownMessage; }
public: // *** static setup method
// call this method to install hooks for the tags needed by
// FlatMessageIO into the given document type
static void AddTo(XML::DocumentType* pDocType);
public: // *** XML formatting
static const char* const s_element;
static const uint16 s_encodeToMax = 72;
static const uint16 s_encodeToMin = 24;
public: // *** IPersistent impl.
// virtual void xmlExport(
// ostream& stream,
// ExportContext& context) const;
// EXPORT:
void xmlExportBegin(
ExportContext& context) const;
void xmlExportAttributes(
ExportContext& context) const;
void xmlExportContent(
ExportContext& context) const;
void xmlExportEnd(
ExportContext& context) const;
// IMPORT:
virtual void xmlImportBegin(
ImportContext& context);
virtual void xmlImportAttribute(
const char* key,
const char* value,
ImportContext& context);
virtual void xmlImportContent(
const char* data,
uint32 length,
ImportContext& context);
virtual void xmlImportChild(
IPersistent* child,
ImportContext& context);
virtual void xmlImportComplete(
ImportContext& context);
private: // *** members
bool m_ownMessage;
BMessage* m_message;
// encoded data is cached here during the import process
BString m_base64Data;
};
__END_CORTEX_NAMESPACE
#endif /*__FlatMessageIO_H__*/

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,132 @@
// MediaFormatIO.h
// * PURPOSE
// Wrapper class for media_format, providing XML
// serialization support using the Cortex::XML package.
//
// * TO DO +++++
// - import & export user data?
// - import & export metadata?
//
// * HISTORY
// e.moon 1jul99 Begun.
#ifndef __MediaFormatIO_H__
#define __MediaFormatIO_H__
#include "XML.h"
#include <MediaDefs.h>
#include <String.h>
#include "cortex_defs.h"
__BEGIN_CORTEX_NAMESPACE
class MediaFormatIO :
public IPersistent {
public: // *** ctor/dtor
virtual ~MediaFormatIO();
MediaFormatIO();
MediaFormatIO(const media_format& format);
public: // *** accessors
// returns B_OK if the object contains a valid format,
// or B_ERROR if not.
status_t getFormat(media_format& outFormat) const;
public: // *** static setup method
// call this method to install hooks for the tags needed by
// MediaFormatIO into the given document type
static void AddTo(XML::DocumentType* pDocType);
public: // *** top-level tags
// these tags map directly to MediaFormatIO
static const char* const s_multi_audio_tag;
static const char* const s_raw_audio_tag;
static const char* const s_raw_video_tag;
static const char* const s_multistream_tag;
static const char* const s_encoded_audio_tag;
static const char* const s_encoded_video_tag;
public: // *** nested tags
static const char* const s_video_display_info_tag;
static const char* const s_multistream_flags_tag;
static const char* const s_multistream_vid_info_tag;
static const char* const s_multistream_avi_info_tag;
static const char* const s_multi_audio_info_tag;
static const char* const s_media_type_tag;
public: // *** IPersistent
// void xmlExport(
// ostream& stream,
// ExportContext& context) const;
// EXPORT:
void xmlExportBegin(
ExportContext& context) const;
void xmlExportAttributes(
ExportContext& context) const;
void xmlExportContent(
ExportContext& context) const;
void xmlExportEnd(
ExportContext& context) const;
// IMPORT
void xmlImportBegin(
ImportContext& context);
void xmlImportAttribute(
const char* key,
const char* value,
ImportContext& context);
void xmlImportContent(
const char* data,
uint32 length,
ImportContext& context);
void xmlImportChild(
IPersistent* child,
ImportContext& context);
void xmlImportComplete(
ImportContext& context);
void xmlImportChildBegin(
const char* name,
ImportContext& context);
void xmlImportChildAttribute(
const char* key,
const char* value,
ImportContext& context);
void xmlImportChildContent(
const char* data,
uint32 length,
ImportContext& context);
void xmlImportChildComplete(
const char* name,
ImportContext& context);
private: // *** state
bool m_complete;
media_format m_format;
BString m_mediaType;
};
__END_CORTEX_NAMESPACE
#endif /*__MediaFormatIO_H__*/

View File

@ -0,0 +1,549 @@
// MessageIO.cpp
#include "MessageIO.h"
#include <Debug.h>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <vector>
#include <utility>
__USE_CORTEX_NAMESPACE
// -------------------------------------------------------- //
// constants
// -------------------------------------------------------- //
const char* const MessageIO::s_element = "BMessage";
const char* _boolEl = "bool";
const char* _int8El = "int8";
const char* _int16El = "int16";
const char* _int32El = "int32";
const char* _int64El = "int64";
const char* _floatEl = "float";
const char* _doubleEl = "double";
const char* _stringEl = "string";
const char* _pointEl = "point";
const char* _rectEl = "rect";
// -------------------------------------------------------- //
// *** ctor/dtor/accessor
// -------------------------------------------------------- //
MessageIO::~MessageIO() {
if(m_ownMessage && m_message)
delete m_message;
}
MessageIO::MessageIO() :
m_ownMessage(true),
m_message(0) {}
// When given a message to export, this object does NOT take
// responsibility for deleting it. It will, however, handle
// deletion of an imported BMessage.
MessageIO::MessageIO(
const BMessage* message) :
m_ownMessage(false),
m_message(const_cast<BMessage*>(message)) {
ASSERT(m_message);
}
void MessageIO::setMessage(
BMessage* message) {
if(m_ownMessage && m_message)
delete m_message;
m_ownMessage = false;
m_message = message;
ASSERT(m_message);
}
// -------------------------------------------------------- //
// *** static setup method
// -------------------------------------------------------- //
// call this method to install hooks for the tags needed by
// MessageIO into the given document type
/*static*/
void MessageIO::AddTo(
XML::DocumentType* docType) {
docType->addMapping(new Mapping<MessageIO>(s_element));
}
// -------------------------------------------------------- //
// EXPORT:
// -------------------------------------------------------- //
void MessageIO::xmlExportBegin(
ExportContext& context) const {
if(!m_message) {
context.reportError("No message data to export.\n");
return;
}
context.beginElement(s_element);
}
void MessageIO::xmlExportAttributes(
ExportContext& context) const {
if(m_message->what)
context.writeAttr("what", m_message->what);
if(m_name.Length())
context.writeAttr("name", m_name.String());
}
void MessageIO::xmlExportContent(
ExportContext& context) const {
ASSERT(m_message);
status_t err;
// +++++ the approach:
// 1) build a list of field names
// 2) export fields sorted first by index, then name
typedef vector<BString> field_set;
field_set fields;
char* name;
type_code type;
int32 count;
for(
int32 n = 0;
m_message->GetInfo(B_ANY_TYPE, n, &name, &type, &count) == B_OK;
++n) {
fields.push_back(name);
}
if(!fields.size())
return;
context.beginContent();
bool done = false;
for(int32 n = 0; !done; ++n) {
done = true;
for(
uint32 fieldIndex = 0;
fieldIndex < fields.size();
++fieldIndex) {
if(m_message->GetInfo(
fields[fieldIndex].String(),
&type,
&count) < B_OK || n >= count)
continue;
// found a field at the current index, so don't give up
done = false;
err = _exportField(
context,
m_message,
type,
fields[fieldIndex].String(),
n);
if(err < B_OK) {
BString errText;
errText << "Couldn't export field '" << fields[fieldIndex] <<
"' index " << n << ": " << strerror(err) << "\n";
context.reportError(errText.String());
return;
}
}
}
}
void MessageIO::xmlExportEnd(
ExportContext& context) const {
context.endElement();
}
// -------------------------------------------------------- //
// IMPORT:
// -------------------------------------------------------- //
void MessageIO::xmlImportBegin(
ImportContext& context) {
// create the message
if(m_message) {
if(m_ownMessage)
delete m_message;
}
m_message = new BMessage();
m_name.SetTo("");
}
void MessageIO::xmlImportAttribute(
const char* key,
const char* value,
ImportContext& context) {
ASSERT(m_message);
if(!strcmp(key, "what"))
m_message->what = atol(value);
else if(!strcmp(key, "name"))
m_name.SetTo(value);
}
void MessageIO::xmlImportContent(
const char* data,
uint32 length,
ImportContext& context) {}
void MessageIO::xmlImportChild(
IPersistent* child,
ImportContext& context) {
ASSERT(m_message);
if(strcmp(context.element(), s_element) != 0) {
context.reportError("Unexpected child element.\n");
return;
}
MessageIO* childMessageIO = dynamic_cast<MessageIO*>(child);
ASSERT(childMessageIO);
m_message->AddMessage(
childMessageIO->m_name.String(),
childMessageIO->m_message);
}
void MessageIO::xmlImportComplete(
ImportContext& context) {}
void MessageIO::xmlImportChildBegin(
const char* name,
ImportContext& context) {
// sanity checks
ASSERT(m_message);
if(strcmp(context.parentElement(), s_element) != 0) {
context.reportError("Unexpected parent element.\n");
return;
}
if(!_isValidMessageElement(context.element())) {
context.reportError("Invalid message field element.\n");
return;
}
m_fieldData.SetTo("");
}
void MessageIO::xmlImportChildAttribute(
const char* key,
const char* value,
ImportContext& context) {
if(!strcmp(key, "name"))
m_fieldName.SetTo(value);
if(!strcmp(key, "value"))
m_fieldData.SetTo(value);
}
void MessageIO::xmlImportChildContent(
const char* data,
uint32 length,
ImportContext& context) {
m_fieldData.Append(data, length);
}
void MessageIO::xmlImportChildComplete(
const char* name,
ImportContext& context) {
ASSERT(m_message);
status_t err = _importField(
m_message,
name,
m_fieldName.String(),
m_fieldData.String());
if(err < B_OK) {
context.reportWarning("Invalid field data.\n");
}
}
// -------------------------------------------------------- //
// implementation
// -------------------------------------------------------- //
bool MessageIO::_isValidMessageElement(
const char* element) const {
if(!strcmp(element, _boolEl)) return true;
if(!strcmp(element, _int8El)) return true;
if(!strcmp(element, _int16El)) return true;
if(!strcmp(element, _int32El)) return true;
if(!strcmp(element, _int64El)) return true;
if(!strcmp(element, _floatEl)) return true;
if(!strcmp(element, _doubleEl)) return true;
if(!strcmp(element, _stringEl)) return true;
if(!strcmp(element, _pointEl)) return true;
if(!strcmp(element, _rectEl)) return true;
return false;
}
status_t MessageIO::_importField(
BMessage* message,
const char* element,
const char* name,
const char* data) {
// skip leading whitespace
while(*data && isspace(*data)) ++data;
if(!strcmp(element, _boolEl)) {
bool v;
if(!strcmp(data, "true") || !strcmp(data, "1"))
v = true;
else if(!strcmp(data, "false") || !strcmp(data, "0"))
v = false;
else
return B_BAD_VALUE;
return message->AddBool(name, v);
}
if(!strcmp(element, _int8El)) {
int8 v = atoi(data);
return message->AddInt8(name, v);
}
if(!strcmp(element, _int16El)) {
int16 v = atoi(data);
return message->AddInt16(name, v);
}
if(!strcmp(element, _int32El)) {
int32 v = atol(data);
return message->AddInt32(name, v);
}
if(!strcmp(element, _int64El)) {
// int64 v = atoll(data);
int64 v = strtoll(data, 0, 10);
return message->AddInt64(name, v);
}
if(!strcmp(element, _floatEl)) {
float v = (float)atof(data);
return message->AddFloat(name, v);
}
if(!strcmp(element, _doubleEl)) {
double v = atof(data);
return message->AddDouble(name, v);
}
if(!strcmp(element, _stringEl)) {
// +++++ chomp leading/trailing whitespace?
return message->AddString(name, data);
}
if(!strcmp(element, _pointEl)) {
BPoint p;
const char* ystart = strchr(data, ',');
if(!ystart)
return B_BAD_VALUE;
++ystart;
if(!*ystart)
return B_BAD_VALUE;
p.x = (float)atof(data);
p.y = (float)atof(ystart);
return message->AddPoint(name, p);
}
if(!strcmp(element, _rectEl)) {
BRect r;
const char* topstart = strchr(data, ',');
if(!topstart)
return B_BAD_VALUE;
++topstart;
if(!*topstart)
return B_BAD_VALUE;
const char* rightstart = strchr(topstart, ',');
if(!rightstart)
return B_BAD_VALUE;
++rightstart;
if(!*rightstart)
return B_BAD_VALUE;
const char* bottomstart = strchr(rightstart, ',');
if(!bottomstart)
return B_BAD_VALUE;
++bottomstart;
if(!*bottomstart)
return B_BAD_VALUE;
r.left = (float)atof(data);
r.top = (float)atof(topstart);
r.right = (float)atof(rightstart);
r.bottom = (float)atof(bottomstart);
return message->AddRect(name, r);
}
return B_BAD_INDEX;
}
status_t MessageIO::_exportField(
ExportContext& context,
BMessage* message,
type_code type,
const char* name,
int32 index) const {
status_t err;
BString elementName;
BString content;
switch(type) {
case B_BOOL_TYPE: {
bool v;
err = message->FindBool(name, index, &v);
if(err < B_OK)
return err;
elementName = _boolEl;
content = (v ? "true" : "false");
break;
}
case B_INT8_TYPE: {
int8 v;
err = message->FindInt8(name, index, &v);
if(err < B_OK)
return err;
elementName = _int8El;
content << (int32)v;
break;
}
case B_INT16_TYPE: {
int16 v;
err = message->FindInt16(name, index, &v);
if(err < B_OK)
return err;
elementName = _int16El;
content << (int32)v;
break;
}
case B_INT32_TYPE: {
int32 v;
err = message->FindInt32(name, index, &v);
if(err < B_OK)
return err;
elementName = _int32El;
content << v;
break;
}
case B_INT64_TYPE: {
int64 v;
err = message->FindInt64(name, index, &v);
if(err < B_OK)
return err;
elementName = _int64El;
content << v;
break;
}
case B_FLOAT_TYPE: {
float v;
err = message->FindFloat(name, index, &v);
if(err < B_OK)
return err;
elementName = _floatEl;
content << v; // +++++ need adjustable precision!
break;
}
case B_DOUBLE_TYPE: {
double v;
err = message->FindDouble(name, index, &v);
if(err < B_OK)
return err;
elementName = _doubleEl;
content << (float)v; // +++++ need adjustable precision!
break;
}
case B_STRING_TYPE: {
const char* v;
err = message->FindString(name, index, &v);
if(err < B_OK)
return err;
elementName = _stringEl;
content = v;
break;
}
case B_POINT_TYPE: {
BPoint v;
err = message->FindPoint(name, index, &v);
if(err < B_OK)
return err;
elementName = _pointEl;
content << v.x << ", " << v.y;
break;
}
case B_RECT_TYPE: {
BRect v;
err = message->FindRect(name, index, &v);
if(err < B_OK)
return err;
elementName = _rectEl;
content << v.left << ", " << v.top << ", " <<
v.right << ", " << v.bottom;
break;
}
case B_MESSAGE_TYPE: {
BMessage m;
err = message->FindMessage(name, index, &m);
if(err < B_OK)
return err;
// write child message
MessageIO io(&m);
io.m_name = name;
return context.writeObject(&io);
}
default:
return B_BAD_TYPE;
}
// spew the element
context.beginElement(elementName.String());
context.writeAttr("name", name);
context.writeAttr("value", content.String());
// context.beginContent();
// context.writeString(content);
context.endElement();
return B_OK;
}
// END -- MessageIO.cpp --

View File

@ -0,0 +1,145 @@
// MessageIO.h
// * PURPOSE
// Export/import of BMessages to and from
// XML using the Cortex persistence library.
// Messages are stored in a user-readable form.
//
// TO DO +++++
// - sanity-check string values (filter/escape single quotes)
//
// * HISTORY
// e.moon 1dec99 Begun.
#ifndef __MessageIO_H__
#define __MessageIO_H__
#include <Message.h>
#include <String.h>
#include "XML.h"
#include "cortex_defs.h"
__BEGIN_CORTEX_NAMESPACE
class MessageIO :
public IPersistent {
public: // *** ctor/dtor/accessor
virtual ~MessageIO();
MessageIO(); //nyi
// When given a message to export, this object does NOT take
// responsibility for deleting it. It will, however, handle
// deletion of an imported BMessage.
MessageIO(
const BMessage* message);
void setMessage(
BMessage* message);
// Returns 0 if no message has been set, and if no message has
// been imported.
const BMessage* message() const { return m_message; }
// Returns true if the message will be automatically deleted.
bool ownsMessage() const { return m_ownMessage; }
public: // *** static setup method
// call this method to install hooks for the tags needed by
// MessageIO into the given document type
static void AddTo(
XML::DocumentType* docType);
public: // *** XML formatting
static const char* const s_element;
public: // *** IPersistent impl.
// EXPORT:
void xmlExportBegin(
ExportContext& context) const;
void xmlExportAttributes(
ExportContext& context) const;
void xmlExportContent(
ExportContext& context) const;
void xmlExportEnd(
ExportContext& context) const;
// IMPORT:
virtual void xmlImportBegin(
ImportContext& context);
virtual void xmlImportAttribute(
const char* key,
const char* value,
ImportContext& context);
virtual void xmlImportContent(
const char* data,
uint32 length,
ImportContext& context);
virtual void xmlImportChild(
IPersistent* child,
ImportContext& context);
virtual void xmlImportComplete(
ImportContext& context);
virtual void xmlImportChildBegin(
const char* name,
ImportContext& context);
virtual void xmlImportChildAttribute(
const char* key,
const char* value,
ImportContext& context);
virtual void xmlImportChildContent(
const char* data,
uint32 length,
ImportContext& context);
virtual void xmlImportChildComplete(
const char* name,
ImportContext& context);
private: // *** members
bool m_ownMessage;
BMessage* m_message;
// name of the message (if used to import a nested BMessage)
BString m_name;
// current field
BString m_fieldName;
BString m_fieldData;
bool _isValidMessageElement(
const char* element) const;
status_t _importField(
BMessage* message,
const char* element,
const char* name,
const char* data);
status_t _exportField(
ExportContext& context,
BMessage* message,
type_code type,
const char* name,
int32 index) const;
};
__END_CORTEX_NAMESPACE
#endif /*__MessageIO_H__*/

View File

@ -0,0 +1,50 @@
B_RGB32
B_RGBA32
B_RGB24
B_RGB16
B_RGB15
B_RGBA15
B_CMAP8
B_GRAY8
B_GRAY1
B_RGB32_BIG
B_RGBA32_BIG
B_RGB24_BIG
B_RGB16_BIG
B_RGB15_BIG
B_RGBA15_BIG
B_RGB32_LITTLE
B_RGBA32_LITTLE
B_RGB24_LITTLE
B_RGB16_LITTLE
B_RGB15_LITTLE
B_RGBA15_LITTLE
B_YCbCr422
B_YCbCr411
B_YCbCr444
B_YCbCr420
B_YUV422
B_YUV411
B_YUV444
B_YUV420
B_YUV9
B_YUV12
B_UVL24
B_UVL32
B_UVLA32
B_LAB24
B_LAB32
B_LABA32
B_HSI24
B_HSI32
B_HSIA32
B_HSV24
B_HSV32
B_HSVA32
B_HLS24
B_HLS32
B_HLSA32
B_CMY24
B_CMY32
B_CMYA32
B_CMYK32

View File

@ -0,0 +1,87 @@
<raw_audio_format
frame_rate = '44100.0'
channel_count = '1'
format = B_AUDIO_UCHAR | B_AUDIO_SHORT | B_AUDIO_FLOAT | B_AUDIO_INT
byte_order = B_MEDIA_BIG_ENDIAN | B_MEDIA_LITTLE_ENDIAN
buffer_size = '1024'
/>
<raw_video_format
field_rate = '30'
interlace = '1'
first_active = '0'
last_active = '239'
orientation = B_VIDEO_TOP_LEFT_RIGHT | B_VIDEO_BOTTOM_LEFT_RIGHT
pixel_width_aspect = '3'
pixel_height_aspect = '4'>
<video_display_info
format = B_RGB32 | B_RGBA32 | B_RGB24 | B_RGB16 | B_RGB15 | B_RGBA15 | B_CMAP8 | B_GRAY8 | B_GRAY1 | <val>
line_width = '320'
line_count = '240'
bytes_per_row = '1280'
pixel_offset = '0'
line_offset = '0'
/>
</raw_video_format>
<multistream_format
format = B_ANY | B_VID | B_AVI | B_MPEG1 | B_MPEG2 | B_QUICKTIME | [val]
avg_bit_rate = '0.0'
max_bit_rate = '0.0'
avg_chunk_size = '0'
max_chunk_size = '0'>
<multistream_flags
header_has_flags = '1' | '0' [def=0]
clean_buffers = '1' | '0' [def=0]
homogenous_buffers = '1' | '0' [def=0]
/>
<!-- either this element -->
<multistream_vid_info
frame_rate = '0.0'
width = '0'
height = '0'
space = [color space]
sampling_rate = '0.0'
sample_format = B_UNDEFINED_SAMPLES | B_LINEAR_SAMPLES | B_FLOAT_SAMPLES | B_MULAW_SAMPLES
byte_order = B_MEDIA_BIG_ENDIAN | B_MEDIA_LITTLE_ENDIAN
channel_count = '0'
/>
<!-- or this one -->
<multistream_avi_info
us_per_frame = '0'
width = '0'
height = '0'>
<!-- up to 5 types may be nested -->
<media_type>B_MEDIA_RAW_AUDIO</media_type>
<media_type>B_MEDIA_RAW_AUDIO</media_type>
<media_type>B_MEDIA_RAW_AUDIO</media_type>
<media_type>B_MEDIA_RAW_AUDIO</media_type>
<media_type>B_MEDIA_RAW_AUDIO</media_type>
</multistream_avi_info>
</multistream_format>
<encoded_audio_format
encoding = B_ANY
bit_rate = '0.0'
frame_size = '0'>
<!-- the output format -->
<raw_audio_format ... />
</encoded_audio_format>
<encoded_video_format
encoding = B_ANY
avg_bit_rate = '0.0'
max_bit_rate = '0.0'
frame_size = '0'
forward_history = '0'
backward_history = '0'>
<!-- output format -->
<raw_video_format ... />
</encoded_video_format>

View File

@ -0,0 +1,281 @@
// XML.cpp
// e.moon 1jul99
#include "XML.h"
#include "Importer.h"
#include <Autolock.h>
#include <Debug.h>
#include "array_delete.h"
#include "set_tools.h"
__USE_CORTEX_NAMESPACE
// -------------------------------------------------------- //
// static members
// -------------------------------------------------------- //
XML::doc_type_map XML::s_docTypeMap;
BLocker XML::s_docTypeLock("XML::s_docTypeLock");
const BMimeType XML::DocumentType::s_defaultMimeType("text/xml");
// -------------------------------------------------------- //
// document type operations
// -------------------------------------------------------- //
// takes responsibility for the given type object
/*static*/
void XML::AddDocumentType(
XML::DocumentType* type) {
ASSERT(type);
BAutolock _l(s_docTypeLock);
// s_docTypeMap.insert(
// make_pair(type->rootElement, type));
s_docTypeMap.insert(
pair<const BString, XML::DocumentType*>(type->rootElement, type));
}
// -------------------------------------------------------- //
// import/export operations
// -------------------------------------------------------- //
// identify object in stream
// returns:
// - B_OK on success, or
// - B_BAD_TYPE if no document type matches the root
// element of the stream, or
// - B_IO_ERROR if the document is malformed, or if a
// read error occurs.
/*static*/
status_t XML::Identify(
BDataIO* stream,
DocumentType** outType,
list<BString>* outErrors) {
ASSERT(stream);
// prepare the input buffer
const uint32 bufferSize = 4096;
char* buffer = new char[bufferSize];
array_delete<char> _d(buffer);
// prepare an Importer to figure document type (from first element)
Importer i(*outErrors);
i.setIdentifyMode();
while(
i.context().state() == ImportContext::PARSING) {
// read chunk (no 0 terminator)
ssize_t readCount = stream->Read(buffer, bufferSize);
if(readCount == 0)
// done
break;
else if(readCount < 0) {
// error
BString err = "Read error: '";
err << strerror(readCount) << "'; ABORTING.";
outErrors->push_back(err);
return B_IO_ERROR;
}
// feed to parser
if(!i.parseBuffer(
buffer, readCount, !stream)) {
break;
}
}
// return found type
if(i.docType()) {
*outType = i.docType();
return B_OK;
}
else return B_BAD_TYPE;
}
// read the root object from the given stream
/*static*/
status_t XML::Read(
BDataIO* stream,
IPersistent** outObject,
list<BString>* outErrors) {
Importer i(*outErrors);
status_t err = _DoRead(stream, i, outErrors);
if(err == B_OK) {
// return completed object
ASSERT(i.target());
*outObject = i.target();
}
return err;
}
/*static*/
status_t XML::Read(
BDataIO* stream,
IPersistent** outObject,
ImportContext* context) {
Importer i(context);
status_t err = _DoRead(stream, i, &context->errors());
if(err == B_OK) {
// return completed object
ASSERT(i.target());
*outObject = i.target();
}
return err;
}
// [e.moon 26nov99]
// populate the provided root object from the given
// XML stream. you need to give the expected root
// (document) element name corresponding to the
// item you provide.
// returns:
// - B_OK on success, or
// - B_IO_ERROR if the document is malformed, or if a
// read error occurs, or
// - B_ERROR
/*static*/
status_t XML::Read(
BDataIO* stream,
IPersistent* rootObject,
XML::DocumentType* documentType,
list<BString>* outErrors) {
Importer i(*outErrors, rootObject, documentType);
return _DoRead(stream, i, outErrors);
}
/*static*/
status_t XML::Read(
BDataIO* stream,
IPersistent* rootObject,
XML::DocumentType* documentType,
ImportContext* context) {
Importer i(context, rootObject, documentType);
return _DoRead(stream, i, &context->errors());
}
/*static*/
status_t XML::_DoRead(
BDataIO* stream,
Importer& i,
list<BString>* outErrors) {
// prepare the input buffer
const uint32 bufferSize = 4096;
char* buffer = new char[bufferSize];
array_delete<char> _d(buffer);
while(
i.context().state() == ImportContext::PARSING) {
// read chunk (no 0 terminator)
ssize_t readCount = stream->Read(buffer, bufferSize);
if(readCount == 0)
// done
break;
else if(readCount < 0) {
// error
BString err = "Read error: '";
err << strerror(readCount) << "'; ABORTING.";
outErrors->push_back(err);
return B_IO_ERROR;
}
// feed to parser
if(!i.parseBuffer(
buffer, readCount, !stream)) {
break;
}
}
status_t err = B_ERROR;
if(i.context().state() == ImportContext::COMPLETE)
err = B_OK;
// clean up
return err;
}
// write the given object to the given stream
/*static*/
status_t XML::Write(
BDataIO* stream,
IPersistent* object,
BString* outError) {
ASSERT(object);
ExportContext context(stream);
status_t err = context.writeObject(object);
if(err < B_OK)
*outError = context.errorText();
return err;
}
// -------------------------------------------------------- //
// XML::DocumentType
// -------------------------------------------------------- //
class _NullMapping : public XMLElementMapping {
public:
_NullMapping(
const char* _element) :
XMLElementMapping(_element) {}
IPersistent* create() const { return 0; }
};
XML::DocumentType::~DocumentType() {
// clean up
ptr_set_delete(m_mappingSet.begin(), m_mappingSet.end());
}
XML::DocumentType::DocumentType(
const char* _rootElement,
const char* _mimeType) :
rootElement(_rootElement),
mimeType(_mimeType ? _mimeType : s_defaultMimeType.Type()) {}
// *** 'factory' interface
// The DocumentType takes ownership of the given mapping
// object. If a mapping for the element already exists,
// the provided object is deleted and the method returns
// B_NAME_IN_USE.
status_t XML::DocumentType::addMapping(
XMLElementMapping* mapping) {
pair<mapping_set::iterator, bool> ret = m_mappingSet.insert(mapping);
if(!ret.second) {
delete mapping;
return B_NAME_IN_USE;
} else
return B_OK;
}
IPersistent* XML::DocumentType::objectFor(
const char* element) {
_NullMapping m(element);
mapping_set::iterator it = m_mappingSet.find(&m);
return (it != m_mappingSet.end()) ?
(*it)->create() : 0;
}
// END -- XML.cpp --

View File

@ -0,0 +1,171 @@
// XML.h
// * PURPOSE
// A central access point for Cortex's XML import/export
// services. A completely static class.
//
// * RESPONSIBILITIES
// - Maintain a set of XML::DocumentType objects, each
// containing the information needed to import a particular
// kind of XML document into native objects.
//
// - Provide a simple API for importing and exporting
// IPersistent objects from/to streams.
//
// * HISTORY
// e.moon 4oct99 API changes:
// - BDataIO used in place of standard streams.
// - Factory folded into XML::DocumentType
//
// e.moon 29jun99 Begun
#ifndef __XML_H__
#define __XML_H__
#include "IPersistent.h"
#include "XMLElementMapping.h"
#include <map>
#include <set>
#include <DataIO.h>
#include <Locker.h>
#include <Mime.h>
#include <String.h>
#include "cortex_defs.h"
__BEGIN_CORTEX_NAMESPACE
// -------------------------------------------------------- //
// class XML
// -------------------------------------------------------- //
class XML {
// internal import helper
friend class Importer;
public: // *** types
class DocumentType;
public: // *** document type operations
// takes responsibility for the given type object
static void AddDocumentType(
XML::DocumentType* type);
public: // *** import/export operations
// identify object in stream.
// returns:
// - B_OK on success, or
// - B_BAD_TYPE if no document type matches the root
// element of the stream, or
// - B_IO_ERROR if the document is malformed, or if a
// read error occurs.
static status_t Identify(
BDataIO* stream,
DocumentType** outType,
list<BString>* outErrors);
// create & populate the root object from the given
// XML stream.
// returns:
// - B_OK on success, or
// - B_IO_ERROR if the document is malformed, or if a
// read error occurs, or
// - B_ERROR
static status_t Read(
BDataIO* stream,
IPersistent** outObject,
list<BString>* outErrors);
static status_t Read(
BDataIO* stream,
IPersistent** outObject,
ImportContext* context); //nyi
// [e.moon 26nov99]
// populate the provided root object from the given
// XML stream. you need to provide a document type
// that corresponds to the given object.
// returns:
// - B_OK on success, or
// - B_IO_ERROR if the document is malformed, or if a
// read error occurs, or
// - B_ERROR
static status_t Read(
BDataIO* stream,
IPersistent* rootObject,
XML::DocumentType* documentType,
list<BString>* outErrors);
static status_t Read(
BDataIO* stream,
IPersistent* rootObject,
XML::DocumentType* documentType,
ImportContext* context);
// create an ExportContext and use it to write the given object
// to the given stream
static status_t Write(
BDataIO* stream,
IPersistent* object,
BString* outError);
private: // static members
typedef map<BString, DocumentType*> doc_type_map;
static doc_type_map s_docTypeMap;
static BLocker s_docTypeLock;
private: // implementation
static status_t _DoRead(
BDataIO* stream,
Importer& i,
list<BString>* outErrors); //nyi
};
// -------------------------------------------------------- //
// class XML::DocumentType
// -------------------------------------------------------- //
class XML::DocumentType {
public: // *** constant members
const BString rootElement;
const BMimeType mimeType;
static const BMimeType s_defaultMimeType;
public: // *** ctor/dtors
virtual ~DocumentType();
DocumentType(
const char* _rootElement,
const char* _mimeType=0);
public: // *** 'factory' interface
// The DocumentType takes ownership of the given mapping
// object. If a mapping for the element already exists,
// the provided object is deleted and the method returns
// B_NAME_IN_USE.
virtual status_t addMapping(
XMLElementMapping* mapping);
// returns 0 if no mapping found for the given element
virtual IPersistent* objectFor(
const char* element);
private: // implementation
typedef set<XMLElementMapping*, _mapping_ptr_less> mapping_set;
mapping_set m_mappingSet;
};
__END_CORTEX_NAMESPACE
#endif /*__XML_H__*/

View File

@ -0,0 +1,62 @@
// XMLElementMapping.h
// * PURPOSE
// A simple class (template implementing a non-template
// base interface) to encapsulate the operation:
// "make an object for this XML element."
//
// * HISTORY
// e.moon 04oct99 Begun.
#ifndef __XMLElementMapping_H__
#define __XMLElementMapping_H__
#include <functional>
#include <String.h>
#include "cortex_defs.h"
__BEGIN_CORTEX_NAMESPACE
class IPersistent;
// The base class:
class XMLElementMapping {
public: // *** data
const BString element;
public: // *** interface
virtual ~XMLElementMapping() {}
XMLElementMapping(
const char* _element) :
element(_element) {}
virtual IPersistent* create() const =0;
};
// The template:
template <class T>
class Mapping :
public XMLElementMapping {
public:
virtual ~Mapping() {}
Mapping(
const char* element) :
XMLElementMapping(element) {}
IPersistent* create() const {
return new T();
}
};
// compare pointers to Mappings by element name
struct _mapping_ptr_less : public binary_function<XMLElementMapping*,XMLElementMapping*,bool> {
public:
bool operator()(const XMLElementMapping* a, const XMLElementMapping* b) const {
return a->element < b->element;
}
};
__END_CORTEX_NAMESPACE
#endif /*__XMLElementMapping_H__*/

View File

@ -0,0 +1,52 @@
// xml_export_utils.h
// * PURPOSE
// helper functions for writing XML representations of
// C++ objects.
//
// * HISTORY
// e.moon 5jul99 Begun
#ifndef __xml_export_utils_H__
#define __xml_export_utils_H__
#include "cortex_defs.h"
__BEGIN_CORTEX_NAMESPACE
// Writes the correct number of spaces to the given stream,
// so that text written after this call will start at the given
// column.
// Assumes that the given text string has already been written
// (with the level of indentation currently stored in the given
// context.)
inline ostream& pad_with_spaces(
ostream& str,
const char* text,
ExportContext& context,
uint16 column=30) {
int16 spaces = column - (strlen(text) + context.indentLevel());
if(spaces < 0) spaces = 0;
while(spaces--) str << ' ';
return str;
}
// Writes the given key/value as an XML attribute (a newline
// is written first, to facilitate compact representation of
// elements with no attributes.)
template <class T>
void write_attr(
const char* key,
T value,
ostream& stream,
ExportContext& context) {
stream << endl << context.indentString() << key;
pad_with_spaces(stream, key, context) << " = '" << value << '\'';
}
__END_CORTEX_NAMESPACE
#endif /*__xml_export_utils_H__*/

Binary file not shown.

View File

@ -0,0 +1,499 @@
// ConnectionIO.cpp
#include "ConnectionIO.h"
#include "LiveNodeIO.h"
#include "NodeManager.h"
#include "NodeSetIOContext.h"
#include "MediaFormatIO.h"
#include "route_app_io.h"
#include <vector>
#include <Debug.h>
__USE_CORTEX_NAMESPACE
// -------------------------------------------------------- //
// *** ctor/dtor
// -------------------------------------------------------- //
ConnectionIO::~ConnectionIO() {
if(m_inputNodeIO) delete m_inputNodeIO;
if(m_outputNodeIO) delete m_outputNodeIO;
}
// initialize for import
ConnectionIO::ConnectionIO() :
m_inputNodeIO(0),
m_outputNodeIO(0),
m_flags(0),
m_exportValid(false),
m_importState(IMPORT_NONE) {
m_outputFormat.type = B_MEDIA_NO_TYPE;
m_inputFormat.type = B_MEDIA_NO_TYPE;
m_requestedFormat.type = B_MEDIA_NO_TYPE;
}
// initialize for export
ConnectionIO::ConnectionIO(
const Connection* con,
const NodeManager* manager,
const NodeSetIOContext* context) :
m_inputNodeIO(0),
m_outputNodeIO(0),
m_exportValid(false),
m_importState(IMPORT_NONE) {
ASSERT(con);
ASSERT(manager);
ASSERT(context);
status_t err;
if(!con->isValid()) {
PRINT((
"!!! ConnectionIO(): invalid connection\n"));
return;
}
m_outputNodeIO = new LiveNodeIO(
manager,
context,
con->sourceNode());
// fetch output (connection-point) description
const char* name;
if(con->getOutputHint(
&name,
&m_outputFormat) == B_OK)
m_outputName = name;
else {
m_outputName = con->outputName();
}
m_inputNodeIO = new LiveNodeIO(
manager,
context,
con->destinationNode());
// fetch input (connection-point) description
if(con->getInputHint(
&name,
&m_inputFormat) == B_OK)
m_inputName = name;
else {
m_inputName = con->inputName();
}
m_requestedFormat = con->requestedFormat();
m_flags = con->flags();
m_exportValid = true;
}
// -------------------------------------------------------- //
// *** operations
// -------------------------------------------------------- //
// call when object imported to create the described
// connection
// +++++ to do
// smarter input/output matching -- if no name/format provided,
// pick the first available endpoint. otherwise, make two passes:
// 1) match all nodes w/ given name (pass wildcards through to roster)
// 2) filter by format
status_t ConnectionIO::instantiate(
NodeManager* manager,
const NodeSetIOContext* context,
Connection* outCon) {
// sanity checks
ASSERT(manager);
if(!m_inputNodeIO || !m_outputNodeIO)
return B_NOT_ALLOWED;
status_t err;
media_node_id node;
// find output node
NodeRef* outputRef;
err = m_outputNodeIO->getNode(manager, context, &node);
if(err < B_OK)
return err;
err = manager->getNodeRef(
node,
&outputRef);
if(err < B_OK)
return err;
// find output +++++ currently matches by name only
const int32 outputBufferSize = 16;
media_output outputs[outputBufferSize];
int32 count = outputBufferSize;
//vector<media_output> outputs;
// err = outputRef->getFreeOutputs(
// outputs/*,
// m_outputFormat.type*/);
err = outputRef->getFreeOutputs(
outputs,
outputBufferSize,
&count);
if(err < B_OK)
return err;
media_output output;
bool found = false;
for(int n = 0; n < count; ++n) {
if(m_outputName == outputs[n].name) {
output = outputs[n];
found = true;
break;
}
}
if(!found) {
PRINT(("!!! output '%s' of node '%s' not found\n",
m_outputName.String(),
outputRef->name()));
return B_NAME_NOT_FOUND;
}
// find input node
NodeRef* inputRef;
err = m_inputNodeIO->getNode(manager, context, &node);
if(err < B_OK)
return err;
err = manager->getNodeRef(
node,
&inputRef);
if(err < B_OK)
return err;
// find input +++++ currently matches by name only
vector<media_input> inputs;
err = inputRef->getFreeInputs(
inputs /*,
m_inputFormat.type*/);
if(err < B_OK)
return err;
media_input input;
found = false;
for(unsigned int n = 0; n < inputs.size(); ++n) {
if(m_inputName == inputs[n].name) {
input = inputs[n];
found = true;
break;
}
}
if(!found) {
PRINT(("!!! input '%s' of node '%s' not found\n",
m_inputName.String(),
inputRef->name()));
return B_NAME_NOT_FOUND;
}
// connect
Connection con;
if(m_requestedFormat.type != B_MEDIA_NO_TYPE)
err = manager->connect(
output,
input,
m_requestedFormat,
&con);
else
err = manager->connect(
output,
input,
&con);
if(err < B_OK)
return err;
if(outCon)
*outCon = con;
return B_OK;
}
// -------------------------------------------------------- //
// *** document-type setup
// -------------------------------------------------------- //
/*static*/
void ConnectionIO::AddTo(
XML::DocumentType* docType) {
// map self
docType->addMapping(new Mapping<ConnectionIO>(_CONNECTION_ELEMENT));
// map simple (content-only) elements
// +++++ should these be added at a higher level, since they're
// shared? no harm is done if one is added more than once,
// since they'll always map to StringContent -- but it's way
// messy!
// +++++
//docType->addMapping(new Mapping<StringContent>(_LIVE_NODE_ELEMENT));
// docType->addMapping(new Mapping<StringContent>(_NAME_ELEMENT));
// docType->addMapping(new Mapping<StringContent>(_KIND_ELEMENT));
// docType->addMapping(new Mapping<StringContent>(_FLAG_ELEMENT));
}
// -------------------------------------------------------- //
// *** IPersistent
// -------------------------------------------------------- //
// -------------------------------------------------------- //
// EXPORT:
// -------------------------------------------------------- //
// -------------------------------------------------------- //
void ConnectionIO::xmlExportBegin(
ExportContext& context) const {
if(!m_exportValid) {
context.reportError(
"ConnectionIO::xmlExportBegin():\n"
"*** invalid ***\n");
return;
}
context.beginElement(_CONNECTION_ELEMENT);
}
void ConnectionIO::xmlExportAttributes(
ExportContext& context) const { TOUCH(context); }
void ConnectionIO::xmlExportContent(
ExportContext& context) const {
context.beginContent();
// write output
{
context.beginElement(_OUTPUT_ELEMENT);
context.beginContent();
// describe the node
// LiveNodeIO nodeIO(
// m_manager,
// dynamic_cast<NodeSetIOContext*>(&context),
// m_outputNode);
context.writeObject(m_outputNodeIO);
// context.beginElement(_LIVE_NODE_ELEMENT);
// if(m_outputNodeKey.Length()) {
// context.writeAttr("key", m_outputNodeKey);
// }
// else {
// _write_simple("name", m_outputNodeName.String(), context);
// _write_node_kinds(m_outputNodeKind, context);
// }
// context.endElement(); // _LIVE_NODE_ELEMENT
// describe the output
_write_simple("name", m_outputName.String(), context);
if(m_outputFormat.type > B_MEDIA_UNKNOWN_TYPE) {
MediaFormatIO io(m_outputFormat);
context.writeObject(&io);
}
context.endElement(); // _OUTPUT_ELEMENT
}
// write input
{
context.beginElement(_INPUT_ELEMENT);
context.beginContent();
// describe the node
// LiveNodeIO nodeIO(
// m_manager,
// dynamic_cast<NodeSetIOContext*>(&context),
// m_inputNode);
context.writeObject(m_inputNodeIO);
// context.beginElement(_LIVE_NODE_ELEMENT);
// if(m_inputNodeKey.Length()) {
// context.writeAttr("key", m_inputNodeKey);
// }
// else {
// _write_simple("name", m_inputNodeName.String(), context);
// _write_node_kinds(m_inputNodeKind, context);
// }
// context.endElement(); // _LIVE_NODE_ELEMENT
// describe the input
_write_simple("name", m_inputName.String(), context);
if(m_inputFormat.type > B_MEDIA_UNKNOWN_TYPE) {
MediaFormatIO io(m_inputFormat);
context.writeObject(&io);
}
context.endElement(); // _INPUT_ELEMENT
}
// write requested format
if(m_requestedFormat.type > B_MEDIA_UNKNOWN_TYPE) {
MediaFormatIO io(m_requestedFormat);
BString comment = "\n";
comment << context.indentString();
comment << "<!-- initial requested format -->";
context.writeString(comment);
context.writeObject(&io);
}
}
void ConnectionIO::xmlExportEnd(
ExportContext& context) const {
context.endElement(); // _CONNECTION_ELEMENT
}
// -------------------------------------------------------- //
// IMPORT:
// -------------------------------------------------------- //
void ConnectionIO::xmlImportBegin(
ImportContext& context) { TOUCH(context); }
void ConnectionIO::xmlImportAttribute(
const char* key,
const char* value,
ImportContext& context) { TOUCH(key); TOUCH(value); TOUCH(context); }
void ConnectionIO::xmlImportContent(
const char* data,
uint32 length,
ImportContext& context) { TOUCH(data); TOUCH(length); TOUCH(context); }
void ConnectionIO::xmlImportChild(
IPersistent* child,
ImportContext& context) {
status_t err;
if(!strcmp(context.element(), _LIVE_NODE_ELEMENT)) {
LiveNodeIO* nodeIO = dynamic_cast<LiveNodeIO*>(child);
ASSERT(nodeIO);
// store the LiveNodeIO for now; it will be used in
// instantiate()
switch(m_importState) {
case IMPORT_OUTPUT:
m_outputNodeIO = nodeIO;
child = 0; // don't delete child object
break;
case IMPORT_INPUT:
m_inputNodeIO = nodeIO;
child = 0; // don't delete child object
break;
case IMPORT_NONE:
context.reportError("Unexpected node description.\n");
delete child;
return;
}
}
else if(!strcmp(context.element(), _NAME_ELEMENT)) {
StringContent* c = dynamic_cast<StringContent*>(child);
ASSERT(c);
switch(m_importState) {
case IMPORT_OUTPUT:
m_outputName = c->content;
break;
case IMPORT_INPUT:
m_inputName = c->content;
break;
case IMPORT_NONE:
context.reportError("Unexpected node name.\n");
delete child;
return;
}
}
else {
MediaFormatIO* io = dynamic_cast<MediaFormatIO*>(child);
if(!io) {
context.reportError("Unexpected element.\n");
delete child;
return;
}
media_format f;
err = io->getFormat(f);
if(err < B_OK) {
context.reportError("Malformed format.\n");
delete child;
return;
}
switch(m_importState) {
case IMPORT_OUTPUT:
m_outputFormat = f;
break;
case IMPORT_INPUT:
m_inputFormat = f;
break;
case IMPORT_NONE:
m_requestedFormat = f;
break;
}
}
if(child)
delete child;
}
void ConnectionIO::xmlImportComplete(
ImportContext& context) {
// +++++
}
void ConnectionIO::xmlImportChildBegin(
const char* name,
ImportContext& context) {
if(!strcmp(name, "input")) {
if(m_importState != IMPORT_NONE) {
context.reportError("ConnectionIO: unexpected nested child element\n");
return;
}
m_importState = IMPORT_INPUT;
}
else if(!strcmp(name, "output")) {
if(m_importState != IMPORT_NONE) {
context.reportError("ConnectionIO: unexpected nested child element\n");
return;
}
m_importState = IMPORT_OUTPUT;
}
else
context.reportError("ConnectionIO: unexpected child element\n");
}
void ConnectionIO::xmlImportChildComplete(
const char* name,
ImportContext& context) {
TOUCH(name); TOUCH(context);
m_importState = IMPORT_NONE;
}
// END -- ConnectionIO.cpp --

View File

@ -0,0 +1,133 @@
// ConnectionIO.h
// * PURPOSE
// Manage the import and export of a user-instantiated
// media node description.
//
// * HISTORY
// e.moon 8dec99 Begun
#ifndef __ConnectionIO_H__
#define __ConnectionIO_H__
#include "NodeRef.h"
#include "Connection.h"
#include "XML.h"
#include <String.h>
#include <Entry.h>
#include <MediaDefs.h>
class dormant_node_info;
#include "cortex_defs.h"
__BEGIN_CORTEX_NAMESPACE
class NodeManager;
class NodeSetIOContext;
class LiveNodeIO;
class ConnectionIO :
public IPersistent {
public: // *** ctor/dtor
virtual ~ConnectionIO();
ConnectionIO();
ConnectionIO(
const Connection* con,
const NodeManager* manager,
const NodeSetIOContext* context);
bool exportValid() const { return m_exportValid; }
public: // *** operations
// call when object imported to create the described
// connection
status_t instantiate(
NodeManager* manager,
const NodeSetIOContext* context,
Connection* outCon);
public: // *** document-type setup
static void AddTo(
XML::DocumentType* docType);
public: // *** IPersistent
// EXPORT:
void xmlExportBegin(
ExportContext& context) const;
void xmlExportAttributes(
ExportContext& context) const;
void xmlExportContent(
ExportContext& context) const;
void xmlExportEnd(
ExportContext& context) const;
// IMPORT:
virtual void xmlImportBegin(
ImportContext& context);
virtual void xmlImportAttribute(
const char* key,
const char* value,
ImportContext& context);
virtual void xmlImportContent(
const char* data,
uint32 length,
ImportContext& context);
virtual void xmlImportChild(
IPersistent* child,
ImportContext& context);
virtual void xmlImportComplete(
ImportContext& context);
virtual void xmlImportChildBegin(
const char* name,
ImportContext& context);
virtual void xmlImportChildComplete(
const char* name,
ImportContext& context);
private: // *** implementation
LiveNodeIO* m_inputNodeIO;
BString m_outputName; // original name if available
media_format m_outputFormat;
LiveNodeIO* m_outputNodeIO;
BString m_inputName; // original name if available
media_format m_inputFormat;
media_format m_requestedFormat;
uint32 m_flags;
bool m_exportValid;
// import state
enum import_state_t {
IMPORT_NONE,
IMPORT_OUTPUT,
IMPORT_INPUT
};
import_state_t m_importState;
};
__END_CORTEX_NAMESPACE
#endif /*__ConnectionIO_H__*/

View File

@ -0,0 +1,538 @@
// DormantNodeIO.cpp
#include "DormantNodeIO.h"
#include "ImportContext.h"
#include "ExportContext.h"
#include "StringContent.h"
#include "NodeManager.h"
#include <Debug.h>
#include <MediaAddOn.h>
#include <MediaDefs.h>
#include <MediaRoster.h>
#include <Path.h>
#include <cstdlib>
#include "route_app_io.h"
__USE_CORTEX_NAMESPACE
// -------------------------------------------------------- //
// *** ctor/dtor
// -------------------------------------------------------- //
DormantNodeIO::~DormantNodeIO() {}
// initialize for import (to defaults)
DormantNodeIO::DormantNodeIO() :
m_kinds(0LL),
m_flavorID(0),
m_flags(0),
m_runMode(0),
m_recordingDelay(0),
m_cycle(false),
m_exportValid(false) {}
// initialize for export
DormantNodeIO::DormantNodeIO(
NodeRef* ref,
const char* nodeKey) :
m_exportValid(false) {
ASSERT(ref);
ASSERT(nodeKey);
status_t err;
m_nodeKey = nodeKey;
// * extract dormant-node info
dormant_node_info info;
err = ref->getDormantNodeInfo(&info);
if(err < B_OK) {
PRINT((
"!!! DormantNodeIO(): getDormantNodeInfo() failed:\n"
" %s\n",
strerror(err)));
return;
}
dormant_flavor_info flavorInfo;
err = BMediaRoster::Roster()->GetDormantFlavorInfoFor(
info, &flavorInfo);
if(err < B_OK) {
PRINT((
"!!! DormantNodeIO(): GetDormantFlavorInfoFor() failed:\n"
" %s\n",
strerror(err)));
return;
}
m_dormantName = flavorInfo.name;
m_flavorID = info.flavor_id;
m_kinds = flavorInfo.kinds;
m_flags = ref->flags();
entry_ref file;
if(ref->getFile(&file) == B_OK)
m_entry.SetTo(&file);
m_runMode = ref->runMode();
m_recordingDelay = ref->recordingDelay();
m_cycle = ref->isCycling();
// done extracting node info; ready for export
m_exportValid = true;
}
// -------------------------------------------------------- //
// *** document-type setup
// -------------------------------------------------------- //
/*static*/
void DormantNodeIO::AddTo(
XML::DocumentType* docType) {
// map self
docType->addMapping(new Mapping<DormantNodeIO>(_DORMANT_NODE_ELEMENT));
// // map simple (content-only) elements
// // +++++ should these be added at a higher level, since they're
// // shared? no harm is done if one is added more than once,
// // since they'll always map to StringContent.
// // +++++
// docType->addMapping(new Mapping<StringContent>(_NAME_ELEMENT));
// docType->addMapping(new Mapping<StringContent>(_KIND_ELEMENT));
// docType->addMapping(new Mapping<StringContent>(_FLAVOR_ID_ELEMENT));
// docType->addMapping(new Mapping<StringContent>(_FLAG_ELEMENT));
// docType->addMapping(new Mapping<StringContent>(_RUN_MODE_ELEMENT));
// docType->addMapping(new Mapping<StringContent>(_RECORDING_DELAY_ELEMENT));
// docType->addMapping(new Mapping<StringContent>(_CYCLE_ELEMENT));
// docType->addMapping(new Mapping<StringContent>(_REF_ELEMENT));
}
// -------------------------------------------------------- //
// *** operations
// -------------------------------------------------------- //
// call when object imported to create the described node
// +++++
status_t DormantNodeIO::instantiate(
NodeManager* manager,
NodeRef** outRef) {
status_t err;
BPath p;
if(m_entry.InitCheck() == B_OK)
m_entry.GetPath(&p);
// PRINT((
// "DormantNodeIO:\n"
// " key: %s\n"
// " name: %s\n"
// " flavor: %ld\n"
// " kinds: %Lx\n"
// " flags: %lx\n"
// " runMode: %ld\n"
// " recDelay: %Ld\n"
// " cycle: %s\n"
// " entry: %s\n\n",
// m_nodeKey.String(),
// m_dormantName.String(),
// m_flavorID,
// m_kinds,
// m_flags,
// m_runMode,
// m_recordingDelay,
// m_cycle ? "true" : "false",
// p.Path()));
// find matching dormant node
dormant_node_info info;
err = _matchDormantNode(&info);
if(err < B_OK) {
PRINT((
"!!! _matchDormantNode() failed: %s\n", strerror(err)));
return err;
}
// instantiate node
err = manager->instantiate(
info,
outRef,
B_INFINITE_TIMEOUT,
m_flags);
if(err < B_OK) {
PRINT((
"!!! instantiate() failed: %s\n", strerror(err)));
return err;
}
entry_ref mediaRef;
if(m_entry.InitCheck() == B_OK && m_entry.GetRef(&mediaRef) == B_OK) {
// set ref
err = (*outRef)->setFile(mediaRef);
if(err < B_OK) {
PRINT((
"!!! WARNING: setFile() failed: %s\n", strerror(err)));
}
}
// set run mode
if(m_runMode)
(*outRef)->setRunMode(m_runMode, m_recordingDelay);
// set cycle state
if(m_cycle)
(*outRef)->setCycling(true);
return B_OK;
}
status_t DormantNodeIO::_matchDormantNode(
dormant_node_info* outInfo) {
status_t err;
// fetch all dormant nodes matching the signature
const int32 bufferSize = 32;
dormant_node_info buffer[bufferSize];
int32 count = bufferSize;
err = BMediaRoster::Roster()->GetDormantNodes(
buffer,
&count,
0,
0,
m_dormantName.String(),
m_kinds,
0 /*~m_kinds*/);
if(err < B_OK)
return err;
if(!count)
return B_NAME_NOT_FOUND;
for(int32 n = 0; n < count; ++n) {
if(buffer[n].flavor_id == m_flavorID) {
*outInfo = buffer[n];
return B_OK;
}
}
// didn't match flavor id
return B_BAD_INDEX;
}
// -------------------------------------------------------- //
// *** IPersistent
// -------------------------------------------------------- //
// -------------------------------------------------------- //
// EXPORT:
// -------------------------------------------------------- //
//inline void _write_simple(
// const char* element,
// const char* value,
// ExportContext& context) {
//
// context.beginElement(element);
// context.beginContent();
// context.writeString(value);
// context.endElement();
//}
// -------------------------------------------------------- //
void DormantNodeIO::xmlExportBegin(
ExportContext& context) const {
if(!m_exportValid) {
context.reportError(
"DormantNodeIO::xmlExportBegin():\n"
"*** invalid ***\n");
return;
}
context.beginElement(_DORMANT_NODE_ELEMENT);
}
void DormantNodeIO::xmlExportAttributes(
ExportContext& context) const {
context.writeAttr("key", m_nodeKey);
}
void DormantNodeIO::xmlExportContent(
ExportContext& context) const {
context.beginContent();
BString buffer;
// write dormant-node description
context.beginElement(_NAME_ELEMENT);
context.beginContent();
context.writeString(m_dormantName);
context.endElement();
if(m_flavorID > 0) {
buffer = "";
buffer << m_flavorID;
context.beginElement(_FLAVOR_ID_ELEMENT);
context.beginContent();
context.writeString(buffer);
context.endElement();
}
_write_node_kinds(m_kinds, context);
// if(m_kinds & B_BUFFER_PRODUCER)
// _write_simple(_KIND_ELEMENT, "B_BUFFER_PRODUCER", context);
// if(m_kinds & B_BUFFER_CONSUMER)
// _write_simple(_KIND_ELEMENT, "B_BUFFER_CONSUMER", context);
// if(m_kinds & B_TIME_SOURCE)
// _write_simple(_KIND_ELEMENT, "B_TIME_SOURCE", context);
// if(m_kinds & B_CONTROLLABLE)
// _write_simple(_KIND_ELEMENT, "B_CONTROLLABLE", context);
// if(m_kinds & B_FILE_INTERFACE)
// _write_simple(_KIND_ELEMENT, "B_FILE_INTERFACE", context);
// if(m_kinds & B_ENTITY_INTERFACE)
// _write_simple(_KIND_ELEMENT, "B_ENTITY_INTERFACE", context);
// if(m_kinds & B_PHYSICAL_INPUT)
// _write_simple(_KIND_ELEMENT, "B_PHYSICAL_INPUT", context);
// if(m_kinds & B_PHYSICAL_OUTPUT)
// _write_simple(_KIND_ELEMENT, "B_PHYSICAL_OUTPUT", context);
// if(m_kinds & B_SYSTEM_MIXER)
// _write_simple(_KIND_ELEMENT, "B_SYSTEM_MIXER", context);
// write NodeRef flags
if(m_flags & NodeRef::NO_START_STOP)
_write_simple(_FLAG_ELEMENT, "NO_START_STOP", context);
if(m_flags & NodeRef::NO_SEEK)
_write_simple(_FLAG_ELEMENT, "NO_SEEK", context);
if(m_flags & NodeRef::NO_PREROLL)
_write_simple(_FLAG_ELEMENT, "NO_PREROLL", context);
if(m_flags & NodeRef::NO_STOP)
_write_simple(_FLAG_ELEMENT, "NO_STOP", context);
if(m_flags & NodeRef::NO_ROSTER_WATCH)
_write_simple(_FLAG_ELEMENT, "NO_ROSTER_WATCH", context);
if(m_flags & NodeRef::NO_POSITION_REPORTING)
_write_simple(_FLAG_ELEMENT, "NO_POSITION_REPORTING", context);
// write transport settings
if(m_runMode > 0) {
switch(m_runMode) {
case BMediaNode::B_OFFLINE:
_write_simple(_RUN_MODE_ELEMENT, "B_OFFLINE", context);
break;
case BMediaNode::B_DECREASE_PRECISION:
_write_simple(_RUN_MODE_ELEMENT, "B_DECREASE_PRECISION", context);
break;
case BMediaNode::B_INCREASE_LATENCY:
_write_simple(_RUN_MODE_ELEMENT, "B_INCREASE_LATENCY", context);
break;
case BMediaNode::B_DROP_DATA:
_write_simple(_RUN_MODE_ELEMENT, "B_DROP_DATA", context);
break;
case BMediaNode::B_RECORDING:
_write_simple(_RUN_MODE_ELEMENT, "B_RECORDING", context);
buffer = "";
buffer << m_recordingDelay;
_write_simple(_RECORDING_DELAY_ELEMENT, buffer.String(), context);
break;
default:
buffer = "";
buffer << m_runMode;
_write_simple(_RUN_MODE_ELEMENT, buffer.String(), context);
}
}
if(m_cycle) {
context.beginElement(_CYCLE_ELEMENT);
context.endElement();
}
BPath p;
if(
m_entry.InitCheck() == B_OK &&
m_entry.GetPath(&p) == B_OK)
_write_simple(_REF_ELEMENT, p.Path(), context);
}
void DormantNodeIO::xmlExportEnd(
ExportContext& context) const {
// finish
context.endElement();
}
// -------------------------------------------------------- //
// IMPORT:
// -------------------------------------------------------- //
//inline void _read_node_kind(
// int64& ioKind,
// const char* data,
// ImportContext& context) {
//
// if(!strcmp(data, "B_BUFFER_PRODUCER"))
// ioKind |= B_BUFFER_PRODUCER;
// else if(!strcmp(data, "B_BUFFER_CONSUMER"))
// ioKind |= B_BUFFER_CONSUMER;
// else if(!strcmp(data, "B_TIME_SOURCE"))
// ioKind |= B_TIME_SOURCE;
// else if(!strcmp(data, "B_CONTROLLABLE"))
// ioKind |= B_CONTROLLABLE;
// else if(!strcmp(data, "B_FILE_INTERFACE"))
// ioKind |= B_FILE_INTERFACE;
// else if(!strcmp(data, "B_ENTITY_INTERFACE"))
// ioKind |= B_ENTITY_INTERFACE;
// else if(!strcmp(data, "B_PHYSICAL_INPUT"))
// ioKind |= B_PHYSICAL_INPUT;
// else if(!strcmp(data, "B_PHYSICAL_OUTPUT"))
// ioKind |= B_PHYSICAL_OUTPUT;
// else if(!strcmp(data, "B_SYSTEM_MIXER"))
// ioKind |= B_SYSTEM_MIXER;
// else {
// BString err;
// err << "_read_noderef_kind(): unknown node kind '" << data << "'\n";
// context.reportWarning(err.String());
// }
//}
inline void _read_noderef_flag(
int32& ioFlags,
const char* data,
ImportContext& context) {
if(!strcmp(data, "NO_START_STOP"))
ioFlags |= NodeRef::NO_START_STOP;
else if(!strcmp(data, "NO_SEEK"))
ioFlags |= NodeRef::NO_SEEK;
else if(!strcmp(data, "NO_PREROLL"))
ioFlags |= NodeRef::NO_PREROLL;
else if(!strcmp(data, "NO_STOP"))
ioFlags |= NodeRef::NO_STOP;
else if(!strcmp(data, "NO_ROSTER_WATCH"))
ioFlags |= NodeRef::NO_ROSTER_WATCH;
else if(!strcmp(data, "NO_POSITION_REPORTING"))
ioFlags |= NodeRef::NO_POSITION_REPORTING;
else {
BString err;
err << "_read_noderef_flag(): unknown node flag '" << data << "'\n";
context.reportWarning(err.String());
}
}
inline void _read_run_mode(
int32& runMode,
const char* data,
ImportContext& context) {
if(!strcmp(data, "B_OFFLINE"))
runMode = BMediaNode::B_OFFLINE;
else if(!strcmp(data, "B_DECREASE_PRECISION"))
runMode = BMediaNode::B_DECREASE_PRECISION;
else if(!strcmp(data, "B_INCREASE_LATENCY"))
runMode = BMediaNode::B_INCREASE_LATENCY;
else if(!strcmp(data, "B_DROP_DATA"))
runMode = BMediaNode::B_DROP_DATA;
else if(!strcmp(data, "B_RECORDING"))
runMode = BMediaNode::B_RECORDING;
else {
BString err;
err << "_read_run_mode(): unknown run mode '" << data << "'\n";
context.reportWarning(err.String());
}
}
inline void _read_entry(
BEntry& entry,
const char* data,
ImportContext& context) {
entry_ref r;
status_t err = get_ref_for_path(data, &r);
if(err < B_OK) {
BString text;
text << "_read_entry_ref(): get_ref_for_path('" << data << "') failed:\n"
" " << strerror(err) << "\n";
context.reportWarning(text.String());
}
entry.SetTo(&r);
}
void DormantNodeIO::xmlImportBegin(
ImportContext& context) { TOUCH(context); }
void DormantNodeIO::xmlImportAttribute(
const char* key,
const char* value,
ImportContext& context) {
if(!strcmp(key, "key")) {
m_nodeKey = value;
}
else {
BString err;
err << "DormantNodeIO: unknown attribute '" << key << "'\n";
context.reportError(err.String());
}
}
void DormantNodeIO::xmlImportContent(
const char* data,
uint32 length,
ImportContext& context) { TOUCH(data); TOUCH(length); TOUCH(context); }
void DormantNodeIO::xmlImportChild(
IPersistent* child,
ImportContext& context) {
StringContent* obj = dynamic_cast<StringContent*>(child);
if(!obj) {
BString err;
err << "DormantNodeIO: unexpected element '" <<
context.element() << "'\n";
context.reportError(err.String());
return;
}
if(!strcmp(context.element(), _NAME_ELEMENT))
m_dormantName = obj->content;
else if(!strcmp(context.element(), _KIND_ELEMENT))
_read_node_kind(m_kinds, obj->content.String(), context);
else if(!strcmp(context.element(), _FLAVOR_ID_ELEMENT))
m_flavorID = atol(obj->content.String());
else if(!strcmp(context.element(), _FLAG_ELEMENT))
_read_noderef_flag(m_flags, obj->content.String(), context);
else if(!strcmp(context.element(), _RUN_MODE_ELEMENT))
_read_run_mode(m_runMode, obj->content.String(), context);
else if(!strcmp(context.element(), _RECORDING_DELAY_ELEMENT))
m_recordingDelay = strtoll(obj->content.String(), 0, 10);
else if(!strcmp(context.element(), _CYCLE_ELEMENT))
m_cycle = true;
else if(!strcmp(context.element(), _REF_ELEMENT))
_read_entry(m_entry, obj->content.String(), context);
else {
BString err;
err << "DormantNodeIO: unexpected element '" <<
context.element() << "'\n";
context.reportError(err.String());
}
delete child;
}
void DormantNodeIO::xmlImportComplete(
ImportContext& context) { TOUCH(context); } //nyi; +++++ final checks?
// END -- DormantNodeIO.cpp --

View File

@ -0,0 +1,111 @@
// DormantNodeIO.h
// * PURPOSE
// Manage the import and export of a user-instantiated
// media node descriptor.
//
// * HISTORY
// e.moon 8dec99 Begun
#ifndef __DormantNodeIO_H__
#define __DormantNodeIO_H__
#include "NodeRef.h"
#include "XML.h"
#include <String.h>
#include <Entry.h>
class dormant_node_info;
#include "cortex_defs.h"
__BEGIN_CORTEX_NAMESPACE
class NodeManager;
class DormantNodeIO :
public IPersistent {
public: // *** ctor/dtor
virtual ~DormantNodeIO();
DormantNodeIO();
DormantNodeIO(
NodeRef* ref,
const char* nodeKey);
bool exportValid() const { return m_exportValid; }
const char* nodeKey() const { return m_nodeKey.String(); }
public: // *** operations
// call when object imported to create the described node
status_t instantiate(
NodeManager* manager,
NodeRef** outRef);
public: // *** document-type setup
static void AddTo(
XML::DocumentType* docType);
public: // *** IPersistent
// EXPORT:
void xmlExportBegin(
ExportContext& context) const;
void xmlExportAttributes(
ExportContext& context) const;
void xmlExportContent(
ExportContext& context) const;
void xmlExportEnd(
ExportContext& context) const;
// IMPORT:
virtual void xmlImportBegin(
ImportContext& context);
virtual void xmlImportAttribute(
const char* key,
const char* value,
ImportContext& context);
virtual void xmlImportContent(
const char* data,
uint32 length,
ImportContext& context);
virtual void xmlImportChild(
IPersistent* child,
ImportContext& context);
virtual void xmlImportComplete(
ImportContext& context);
private: // *** implementation
// imported data
BString m_nodeKey;
BString m_dormantName;
int64 m_kinds;
int32 m_flavorID;
int32 m_flags;
int32 m_runMode;
bigtime_t m_recordingDelay;
bool m_cycle;
BEntry m_entry;
bool m_exportValid;
status_t _matchDormantNode(
dormant_node_info* outInfo);
};
__END_CORTEX_NAMESPACE
#endif /*__DormantNodeIO_H__*/

View File

@ -0,0 +1,215 @@
// LiveNodeIO.cpp
#include "LiveNodeIO.h"
#include "ImportContext.h"
#include "ExportContext.h"
#include "NodeSetIOContext.h"
#include "StringContent.h"
#include "NodeManager.h"
#include <Debug.h>
#include <MediaAddOn.h>
#include <MediaDefs.h>
#include <MediaRoster.h>
#include <Path.h>
#include "route_app_io.h"
__USE_CORTEX_NAMESPACE
// -------------------------------------------------------- //
// *** ctor/dtor
// -------------------------------------------------------- //
LiveNodeIO::~LiveNodeIO() {}
LiveNodeIO::LiveNodeIO() :
m_kind(0LL),
m_exportValid(false) {}
LiveNodeIO::LiveNodeIO(
const NodeManager* manager,
const NodeSetIOContext* context,
media_node_id node) :
m_exportValid(false) {
status_t err;
ASSERT(manager);
ASSERT(context);
err = _get_node_signature(
manager,
context,
node,
m_key,
m_name,
m_kind);
if(err < B_OK)
return;
m_exportValid = true;
}
// -------------------------------------------------------- //
// *** import operations
// -------------------------------------------------------- //
// locate the referenced live node
status_t LiveNodeIO::getNode(
const NodeManager* manager,
const NodeSetIOContext* context,
media_node_id* outNode) const {
ASSERT(manager);
ASSERT(context);
status_t err;
if(hasKey()) {
// match key against previously imported nodes
err = context->getNodeFor(key(), outNode);
if(err < B_OK) {
// match key against system nodes
err = _match_system_node_key(key(), manager, outNode);
if(err < B_OK) {
PRINT((
"!!! No node found for key '%s'\n",
key()));
return B_NAME_NOT_FOUND;
}
}
}
else {
err = _match_node_signature(
name(),
kind(),
outNode);
if(err < B_OK) {
PRINT((
"!!! No node found named '%s' with kinds %Ld\n",
name(),
kind()));
return B_NAME_NOT_FOUND;
}
}
return B_OK;
}
// -------------------------------------------------------- //
// *** document-type setup
// -------------------------------------------------------- //
/*static*/
void LiveNodeIO::AddTo(
XML::DocumentType* docType) {
// map self
docType->addMapping(new Mapping<LiveNodeIO>(_LIVE_NODE_ELEMENT));
}
// -------------------------------------------------------- //
// *** IPersistent
// -------------------------------------------------------- //
// -------------------------------------------------------- //
// EXPORT:
// -------------------------------------------------------- //
void LiveNodeIO::xmlExportBegin(
ExportContext& context) const {
if(!m_exportValid) {
context.reportError(
"LiveNodeIO::xmlExportBegin():\n"
"*** invalid ***\n");
return;
}
context.beginElement(_LIVE_NODE_ELEMENT);
}
void LiveNodeIO::xmlExportAttributes(
ExportContext& context) const {
if(m_key.Length() > 0)
context.writeAttr("key", m_key.String());
}
void LiveNodeIO::xmlExportContent(
ExportContext& context) const {
if(m_name.Length() > 0) {
context.beginContent();
_write_simple(_NAME_ELEMENT, m_name.String(), context);
_write_node_kinds(m_kind, context);
}
}
void LiveNodeIO::xmlExportEnd(
ExportContext& context) const {
context.endElement();
}
// -------------------------------------------------------- //
// IMPORT:
// -------------------------------------------------------- //
void LiveNodeIO::xmlImportBegin(
ImportContext& context) {}
void LiveNodeIO::xmlImportAttribute(
const char* key,
const char* value,
ImportContext& context) {
if(!strcmp(key, "key")) {
m_key = value;
}
else {
BString err;
err << "LiveNodeIO: unknown attribute '" << key << "'\n";
context.reportError(err.String());
}
}
void LiveNodeIO::xmlImportContent(
const char* data,
uint32 length,
ImportContext& context) {}
void LiveNodeIO::xmlImportChild(
IPersistent* child,
ImportContext& context) {
StringContent* obj = dynamic_cast<StringContent*>(child);
if(!obj) {
BString err;
err << "LiveNodeIO: unexpected element '" <<
context.element() << "'\n";
context.reportError(err.String());
return;
}
if(!strcmp(context.element(), _NAME_ELEMENT))
m_name = obj->content;
else if(!strcmp(context.element(), _KIND_ELEMENT))
_read_node_kind(m_kind, obj->content.String(), context);
else {
BString err;
err << "LiveNodeIO: unexpected element '" <<
context.element() << "'\n";
context.reportError(err.String());
}
delete child;
}
void LiveNodeIO::xmlImportComplete(
ImportContext& context) {}
// END -- LiveNodeIO.cpp --

View File

@ -0,0 +1,129 @@
// LiveNodeIO.h
// * PURPOSE
// Manage the import and export of an 'existing node'
// descriptor -- which refers to a system node
// (video input, audio mixer, etc.,) a dormant node
// described in the same document, or some other external
// node.
//
// In the first two cases, the node is described by a key
// string; the following preset key strings correspond to
// system nodes:
//
// AUDIO_INPUT
// AUDIO_OUTPUT
// AUDIO_MIXER
// VIDEO_INPUT
// VIDEO_OUTPUT
// DAC_TIME_SOURCE
// SYSTEM_TIME_SOURCE
//
// There's no way to describe a particular live node instance
// in a persistent fashion (an instance of the same node created
// in the future will have a different node ID.) At the moment,
// LiveNodeIO describes such nodes via two pieces of information:
// - the node name
// - the node's 'kind' bitmask
//
// * HISTORY
// e.moon 20dec99 begun
#ifndef __LiveNodeIO_H__
#define __LiveNodeIO_H__
#include "NodeRef.h"
#include "XML.h"
#include <String.h>
#include <Entry.h>
#include "cortex_defs.h"
__BEGIN_CORTEX_NAMESPACE
class NodeManager;
class NodeSetIOContext;
class LiveNodeIO :
public IPersistent {
public: // *** ctor/dtor
virtual ~LiveNodeIO();
LiveNodeIO();
LiveNodeIO(
const NodeManager* manager,
const NodeSetIOContext* context,
media_node_id node);
bool exportValid() const { return m_exportValid; }
// if true, call key() to fetch the key string; otherwise,
// call name()/kind()
bool hasKey() const { return m_key.Length() > 0; }
const char* key() const { return m_key.String(); }
const char* name() const { return m_name.String(); }
int64 kind() const { return m_kind; }
public: // *** import operations
// locate the referenced live node
status_t getNode(
const NodeManager* manager,
const NodeSetIOContext* context,
media_node_id* outNode) const;
public: // *** document-type setup
static void AddTo(
XML::DocumentType* docType);
public: // *** IPersistent
// EXPORT:
void xmlExportBegin(
ExportContext& context) const;
void xmlExportAttributes(
ExportContext& context) const;
void xmlExportContent(
ExportContext& context) const;
void xmlExportEnd(
ExportContext& context) const;
// IMPORT:
void xmlImportBegin(
ImportContext& context);
void xmlImportAttribute(
const char* key,
const char* value,
ImportContext& context);
void xmlImportContent(
const char* data,
uint32 length,
ImportContext& context);
void xmlImportChild(
IPersistent* child,
ImportContext& context);
void xmlImportComplete(
ImportContext& context);
private: // *** implementation
BString m_key;
BString m_name;
int64 m_kind;
bool m_exportValid;
};
__END_CORTEX_NAMESPACE
#endif /*__LiveNodeIO_H__*/

View File

@ -0,0 +1,48 @@
// NodeExportContext.h
// * PURPOSE
// Extends ExportContext to include a set of nodes
// to be stored. This is an abstract class; implement
// exportUIState() to store any user-interface state
// info needed for the listed nodes.
//
// TO DO ++++++ GO AWAY! NodeSetIOContext provides the same
// functionality for both import and export...
//
// * HISTORY
// e.moon 7dec99 Begun
#ifndef __NodeExportContext_H__
#define __NodeExportContext_H__
#include <vector>
#include "ExportContext.h"
#include "IStateArchivable.h"
#include "cortex_defs.h"
__BEGIN_CORTEX_NAMESPACE
class NodeExportContext :
public ExportContext {
public: // *** dtor/ctor
virtual ~NodeExportContext() {}
NodeExportContext(
BDataIO* _stream,
BString& error) :
ExportContext(_stream, error) {}
public: // *** members
// set of nodes to export; if one or more nodes are
// not fit to be exported, they may be removed or
// set to media_node::null.node during the export process.
typedef vector<media_node_id> media_node_set;
media_node_set nodes;
public: // *** interface
virtual void exportUIState(
BMessage* archive) =0;
};
__END_CORTEX_NAMESPACE
#endif /*__NodeExportContext_H__*/

Some files were not shown because too many files have changed in this diff Show More