/*
* Copyright 2006-2009, Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Stephan Aßmus <superstippi@gmx.de>
*/
#include "TransformerListView.h"
#include <new>
#include <stdio.h>
#include <Application.h>
#include <Catalog.h>
#include <ListItem.h>
#include <Locale.h>
#include <Menu.h>
#include <MenuItem.h>
#include <Mime.h>
#include <Message.h>
#include <Window.h>
#include "AddTransformersCommand.h"
#include "CommandStack.h"
#include "MoveTransformersCommand.h"
#include "RemoveTransformersCommand.h"
#include "Transformer.h"
#include "TransformerFactory.h"
#include "Observer.h"
#include "Selection.h"
#undef B_TRANSLATION_CONTEXT
#define B_TRANSLATION_CONTEXT "Icon-O-Matic-TransformersList"
using std::nothrow;
class TransformerItem : public SimpleItem,
public Observer {
public:
TransformerItem(Transformer* t,
TransformerListView* listView)
: SimpleItem(t->Name()),
transformer(NULL),
fListView(listView)
{
SetTransformer(t);
}
virtual ~TransformerItem()
{
SetTransformer(NULL);
}
// Observer interface
virtual void ObjectChanged(const Observable* object)
{
UpdateText();
}
// TransformerItem
void SetTransformer(Transformer* t)
{
if (t == transformer)
return;
if (transformer) {
transformer->RemoveObserver(this);
transformer->ReleaseReference();
}
transformer = t;
if (transformer) {
transformer->AcquireReference();
transformer->AddObserver(this);
UpdateText();
}
}
void UpdateText()
{
SetText(transformer->Name());
// :-/
if (fListView->LockLooper()) {
fListView->InvalidateItem(
fListView->IndexOf(this));
fListView->UnlockLooper();
}
}
Transformer* transformer;
private:
TransformerListView* fListView;
};
// #pragma mark -
enum {
MSG_DRAG_TRANSFORMER = 'drgt',
MSG_ADD_TRANSFORMER = 'adtr',
};
// constructor
TransformerListView::TransformerListView(BRect frame, const char* name,
BMessage* message, BHandler* target)
: SimpleListView(frame, name,
NULL, B_MULTIPLE_SELECTION_LIST),
fMessage(message),
fShape(NULL),
fCommandStack(NULL)
{
SetDragCommand(MSG_DRAG_TRANSFORMER);
SetTarget(target);
}
// destructor
TransformerListView::~TransformerListView()
{
_MakeEmpty();
delete fMessage;
if (fShape)
fShape->RemoveListener(this);
}
// Draw
void
TransformerListView::Draw(BRect updateRect)
{
SimpleListView::Draw(updateRect);
if (fShape)
return;
// display helpful messages
const char* message1 = B_TRANSLATE_CONTEXT("Click on a shape above",
"Empty transformers list - 1st line");
const char* message2 = B_TRANSLATE_CONTEXT("to attach transformers.",
"Empty transformers list - 2nd line");
// Dark Themes
rgb_color lowColor = LowColor();
if (lowColor.red + lowColor.green + lowColor.blue > 128 * 3)
SetHighColor(tint_color(LowColor(), B_DARKEN_2_TINT));
else
SetHighColor(tint_color(LowColor(), B_LIGHTEN_2_TINT));
font_height fh;
GetFontHeight(&fh);
BRect b(Bounds());
BPoint middle;
float textHeight = (fh.ascent + fh.descent) * 1.5;
middle.y = (b.top + b.bottom - textHeight) / 2.0;
middle.x = (b.left + b.right - StringWidth(message1)) / 2.0;
DrawString(message1, middle);
middle.y += textHeight;
middle.x = (b.left + b.right - StringWidth(message2)) / 2.0;
DrawString(message2, middle);
}
// SelectionChanged
void
TransformerListView::SelectionChanged()
{
if (CountSelectedItems() > 0)
SimpleListView::SelectionChanged();
// else
// TODO: any selected transformer will still be visible in the
// PropertyListView
if (!fSyncingToSelection) {
TransformerItem* item
= dynamic_cast<TransformerItem*>(ItemAt(CurrentSelection(0)));
if (fMessage) {
BMessage message(*fMessage);
message.AddPointer("transformer", item ? (void*)item->transformer : NULL);
Invoke(&message);
}
}
}
// MessageReceived
void
TransformerListView::MessageReceived(BMessage* message)
{
switch (message->what) {
case MSG_ADD_TRANSFORMER: {
if (!fShape || !fCommandStack)
break;
uint32 type;
if (message->FindInt32("type", (int32*)&type) < B_OK)
break;
Transformer* transformer
= TransformerFactory::TransformerFor(type,
fShape->VertexSource());
if (!transformer)
break;
Transformer* transformers[1];
transformers[0] = transformer;
::Command* command = new (nothrow) AddTransformersCommand(
fShape, transformers, 1, fShape->CountTransformers());
if (!command)
delete transformer;
fCommandStack->Perform(command);
break;
}
default:
SimpleListView::MessageReceived(message);
break;
}
}
// MakeDragMessage
void
TransformerListView::MakeDragMessage(BMessage* message) const
{
SimpleListView::MakeDragMessage(message);
message->AddPointer("container", fShape);
int32 count = CountItems();
for (int32 i = 0; i < count; i++) {
TransformerItem* item = dynamic_cast<TransformerItem*>(ItemAt(CurrentSelection(i)));
if (item) {
message->AddPointer("transformer", (void*)item->transformer);
} else
break;
}
}
// #pragma mark -
// MoveItems
void
TransformerListView::MoveItems(BList& items, int32 toIndex)
{
if (!fCommandStack || !fShape)
return;
int32 count = items.CountItems();
Transformer** transformers = new (nothrow) Transformer*[count];
if (!transformers)
return;
for (int32 i = 0; i < count; i++) {
TransformerItem* item
= dynamic_cast<TransformerItem*>((BListItem*)items.ItemAtFast(i));
transformers[i] = item ? item->transformer : NULL;
}
MoveTransformersCommand* command
= new (nothrow) MoveTransformersCommand(fShape,
transformers, count, toIndex);
if (!command) {
delete[] transformers;
return;
}
fCommandStack->Perform(command);
}
// CopyItems
void
TransformerListView::CopyItems(BList& items, int32 toIndex)
{
MoveItems(items, toIndex);
// TODO: allow copying items
}
// RemoveItemList
void
TransformerListView::RemoveItemList(BList& items)
{
if (!fCommandStack || !fShape)
return;
int32 count = items.CountItems();
int32 indices[count];
for (int32 i = 0; i < count; i++)
indices[i] = IndexOf((BListItem*)items.ItemAtFast(i));
RemoveTransformersCommand* command
= new (nothrow) RemoveTransformersCommand(fShape,
indices, count);
fCommandStack->Perform(command);
}
// CloneItem
BListItem*
TransformerListView::CloneItem(int32 index) const
{
if (TransformerItem* item = dynamic_cast<TransformerItem*>(ItemAt(index))) {
return new TransformerItem(item->transformer,
const_cast<TransformerListView*>(this));
}
return NULL;
}
// IndexOfSelectable
int32
TransformerListView::IndexOfSelectable(Selectable* selectable) const
{
Transformer* transformer = dynamic_cast<Transformer*>(selectable);
if (!transformer)
return -1;
for (int32 i = 0;
TransformerItem* item = dynamic_cast<TransformerItem*>(ItemAt(i));
i++) {
if (item->transformer == transformer)
return i;
}
return -1;
}
// SelectableFor
Selectable*
TransformerListView::SelectableFor(BListItem* item) const
{
TransformerItem* transformerItem = dynamic_cast<TransformerItem*>(item);
if (transformerItem)
return transformerItem->transformer;
return NULL;
}
// #pragma mark -
// TransformerAdded
void
TransformerListView::TransformerAdded(Transformer* transformer, int32 index)
{
// NOTE: we are in the thread that messed with the
// Shape, so no need to lock the document, when this is
// changed to asynchronous notifications, then it would
// need to be read-locked!
if (!LockLooper())
return;
_AddTransformer(transformer, index);
UnlockLooper();
}
// TransformerRemoved
void
TransformerListView::TransformerRemoved(Transformer* transformer)
{
// NOTE: we are in the thread that messed with the
// Shape, so no need to lock the document, when this is
// changed to asynchronous notifications, then it would
// need to be read-locked!
if (!LockLooper())
return;
_RemoveTransformer(transformer);
UnlockLooper();
}
// StyleChanged
void
TransformerListView::StyleChanged(Style* oldStyle, Style* newStyle)
{
// we don't care
}
// #pragma mark -
// SetMenu
void
TransformerListView::SetMenu(BMenu* menu)
{
if (fMenu == menu)
return;
fMenu = menu;
if (fMenu == NULL)
return;
BMenu* addMenu = new BMenu(B_TRANSLATE("Add"));
int32 cookie = 0;
uint32 type;
BString name;
while (TransformerFactory::NextType(&cookie, &type, &name)) {
// TODO: Disable the "Transformation" and "Perspective" transformers
// since they are not very useful or even implemented at all.
if (name == B_TRANSLATE("Transformation")
|| name == B_TRANSLATE("Perspective"))
continue;
// End of TODO.
BMessage* message = new BMessage(MSG_ADD_TRANSFORMER);
message->AddInt32("type", type);
addMenu->AddItem(new BMenuItem(name.String(), message));
}
addMenu->SetTargetForItems(this);
fMenu->AddItem(addMenu);
_UpdateMenu();
}
// SetShape
void
TransformerListView::SetShape(Shape* shape)
{
if (fShape == shape)
return;
// detach from old container
if (fShape)
fShape->RemoveListener(this);
_MakeEmpty();
fShape = shape;
if (fShape) {
fShape->AddListener(this);
int32 count = fShape->CountTransformers();
for (int32 i = 0; i < count; i++)
_AddTransformer(fShape->TransformerAtFast(i), i);
}
_UpdateMenu();
}
// SetCommandStack
void
TransformerListView::SetCommandStack(CommandStack* stack)
{
fCommandStack = stack;
}
// #pragma mark -
// _AddTransformer
bool
TransformerListView::_AddTransformer(Transformer* transformer, int32 index)
{
if (transformer)
return AddItem(new TransformerItem(transformer, this), index);
return false;
}
// _RemoveTransformer
bool
TransformerListView::_RemoveTransformer(Transformer* transformer)
{
TransformerItem* item = _ItemForTransformer(transformer);
if (item && RemoveItem(item)) {
delete item;
return true;
}
return false;
}
// _ItemForTransformer
TransformerItem*
TransformerListView::_ItemForTransformer(Transformer* transformer) const
{
for (int32 i = 0;
TransformerItem* item = dynamic_cast<TransformerItem*>(ItemAt(i));
i++) {
if (item->transformer == transformer)
return item;
}
return NULL;
}
// _UpdateMenu
void
TransformerListView::_UpdateMenu()
{
fMenu->SetEnabled(fShape != NULL);
}
↑ V730 Not all members of a class are initialized inside the constructor. Consider inspecting: fMenu.