HaikuDepot: notify work status from main window
[haiku.git] / src / apps / icon-o-matic / gui / TransformerListView.cpp
blob22c5adbaf1353d28539e85052074f0c9f3ff8981
1 /*
2 * Copyright 2006-2009, Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
5 * Authors:
6 * Stephan Aßmus <superstippi@gmx.de>
7 */
9 #include "TransformerListView.h"
11 #include <new>
12 #include <stdio.h>
14 #include <Application.h>
15 #include <Catalog.h>
16 #include <ListItem.h>
17 #include <Locale.h>
18 #include <Menu.h>
19 #include <MenuItem.h>
20 #include <Mime.h>
21 #include <Message.h>
22 #include <Window.h>
24 #include "AddTransformersCommand.h"
25 #include "CommandStack.h"
26 #include "MoveTransformersCommand.h"
27 #include "RemoveTransformersCommand.h"
28 #include "Transformer.h"
29 #include "TransformerFactory.h"
30 #include "Observer.h"
31 #include "Selection.h"
34 #undef B_TRANSLATION_CONTEXT
35 #define B_TRANSLATION_CONTEXT "Icon-O-Matic-TransformersList"
38 using std::nothrow;
40 class TransformerItem : public SimpleItem,
41 public Observer {
42 public:
43 TransformerItem(Transformer* t,
44 TransformerListView* listView)
45 : SimpleItem(t->Name()),
46 transformer(NULL),
47 fListView(listView)
49 SetTransformer(t);
52 virtual ~TransformerItem()
54 SetTransformer(NULL);
57 // Observer interface
58 virtual void ObjectChanged(const Observable* object)
60 UpdateText();
63 // TransformerItem
64 void SetTransformer(Transformer* t)
66 if (t == transformer)
67 return;
69 if (transformer) {
70 transformer->RemoveObserver(this);
71 transformer->ReleaseReference();
74 transformer = t;
76 if (transformer) {
77 transformer->AcquireReference();
78 transformer->AddObserver(this);
79 UpdateText();
82 void UpdateText()
84 SetText(transformer->Name());
85 // :-/
86 if (fListView->LockLooper()) {
87 fListView->InvalidateItem(
88 fListView->IndexOf(this));
89 fListView->UnlockLooper();
93 Transformer* transformer;
94 private:
95 TransformerListView* fListView;
98 // #pragma mark -
100 enum {
101 MSG_DRAG_TRANSFORMER = 'drgt',
102 MSG_ADD_TRANSFORMER = 'adtr',
105 // constructor
106 TransformerListView::TransformerListView(BRect frame, const char* name,
107 BMessage* message, BHandler* target)
108 : SimpleListView(frame, name,
109 NULL, B_MULTIPLE_SELECTION_LIST),
110 fMessage(message),
111 fShape(NULL),
112 fCommandStack(NULL)
114 SetDragCommand(MSG_DRAG_TRANSFORMER);
115 SetTarget(target);
118 // destructor
119 TransformerListView::~TransformerListView()
121 _MakeEmpty();
122 delete fMessage;
124 if (fShape)
125 fShape->RemoveListener(this);
128 // Draw
129 void
130 TransformerListView::Draw(BRect updateRect)
132 SimpleListView::Draw(updateRect);
134 if (fShape)
135 return;
137 // display helpful messages
138 const char* message1 = B_TRANSLATE_CONTEXT("Click on a shape above",
139 "Empty transformers list - 1st line");
140 const char* message2 = B_TRANSLATE_CONTEXT("to attach transformers.",
141 "Empty transformers list - 2nd line");
143 // Dark Themes
144 rgb_color lowColor = LowColor();
145 if (lowColor.red + lowColor.green + lowColor.blue > 128 * 3)
146 SetHighColor(tint_color(LowColor(), B_DARKEN_2_TINT));
147 else
148 SetHighColor(tint_color(LowColor(), B_LIGHTEN_2_TINT));
150 font_height fh;
151 GetFontHeight(&fh);
152 BRect b(Bounds());
154 BPoint middle;
155 float textHeight = (fh.ascent + fh.descent) * 1.5;
156 middle.y = (b.top + b.bottom - textHeight) / 2.0;
157 middle.x = (b.left + b.right - StringWidth(message1)) / 2.0;
158 DrawString(message1, middle);
160 middle.y += textHeight;
161 middle.x = (b.left + b.right - StringWidth(message2)) / 2.0;
162 DrawString(message2, middle);
165 // SelectionChanged
166 void
167 TransformerListView::SelectionChanged()
169 if (CountSelectedItems() > 0)
170 SimpleListView::SelectionChanged();
171 // else
172 // TODO: any selected transformer will still be visible in the
173 // PropertyListView
175 if (!fSyncingToSelection) {
176 TransformerItem* item
177 = dynamic_cast<TransformerItem*>(ItemAt(CurrentSelection(0)));
178 if (fMessage) {
179 BMessage message(*fMessage);
180 message.AddPointer("transformer", item ? (void*)item->transformer : NULL);
181 Invoke(&message);
186 // MessageReceived
187 void
188 TransformerListView::MessageReceived(BMessage* message)
190 switch (message->what) {
191 case MSG_ADD_TRANSFORMER: {
192 if (!fShape || !fCommandStack)
193 break;
195 uint32 type;
196 if (message->FindInt32("type", (int32*)&type) < B_OK)
197 break;
199 Transformer* transformer
200 = TransformerFactory::TransformerFor(type,
201 fShape->VertexSource());
202 if (!transformer)
203 break;
205 Transformer* transformers[1];
206 transformers[0] = transformer;
207 ::Command* command = new (nothrow) AddTransformersCommand(
208 fShape, transformers, 1, fShape->CountTransformers());
210 if (!command)
211 delete transformer;
213 fCommandStack->Perform(command);
214 break;
216 default:
217 SimpleListView::MessageReceived(message);
218 break;
222 // MakeDragMessage
223 void
224 TransformerListView::MakeDragMessage(BMessage* message) const
226 SimpleListView::MakeDragMessage(message);
227 message->AddPointer("container", fShape);
228 int32 count = CountItems();
229 for (int32 i = 0; i < count; i++) {
230 TransformerItem* item = dynamic_cast<TransformerItem*>(ItemAt(CurrentSelection(i)));
231 if (item) {
232 message->AddPointer("transformer", (void*)item->transformer);
233 } else
234 break;
238 // #pragma mark -
240 // MoveItems
241 void
242 TransformerListView::MoveItems(BList& items, int32 toIndex)
244 if (!fCommandStack || !fShape)
245 return;
247 int32 count = items.CountItems();
248 Transformer** transformers = new (nothrow) Transformer*[count];
249 if (!transformers)
250 return;
252 for (int32 i = 0; i < count; i++) {
253 TransformerItem* item
254 = dynamic_cast<TransformerItem*>((BListItem*)items.ItemAtFast(i));
255 transformers[i] = item ? item->transformer : NULL;
258 MoveTransformersCommand* command
259 = new (nothrow) MoveTransformersCommand(fShape,
260 transformers, count, toIndex);
261 if (!command) {
262 delete[] transformers;
263 return;
266 fCommandStack->Perform(command);
269 // CopyItems
270 void
271 TransformerListView::CopyItems(BList& items, int32 toIndex)
273 MoveItems(items, toIndex);
274 // TODO: allow copying items
277 // RemoveItemList
278 void
279 TransformerListView::RemoveItemList(BList& items)
281 if (!fCommandStack || !fShape)
282 return;
284 int32 count = items.CountItems();
285 int32 indices[count];
286 for (int32 i = 0; i < count; i++)
287 indices[i] = IndexOf((BListItem*)items.ItemAtFast(i));
289 RemoveTransformersCommand* command
290 = new (nothrow) RemoveTransformersCommand(fShape,
291 indices, count);
292 fCommandStack->Perform(command);
295 // CloneItem
296 BListItem*
297 TransformerListView::CloneItem(int32 index) const
299 if (TransformerItem* item = dynamic_cast<TransformerItem*>(ItemAt(index))) {
300 return new TransformerItem(item->transformer,
301 const_cast<TransformerListView*>(this));
303 return NULL;
306 // IndexOfSelectable
307 int32
308 TransformerListView::IndexOfSelectable(Selectable* selectable) const
310 Transformer* transformer = dynamic_cast<Transformer*>(selectable);
311 if (!transformer)
312 return -1;
314 for (int32 i = 0;
315 TransformerItem* item = dynamic_cast<TransformerItem*>(ItemAt(i));
316 i++) {
317 if (item->transformer == transformer)
318 return i;
321 return -1;
324 // SelectableFor
325 Selectable*
326 TransformerListView::SelectableFor(BListItem* item) const
328 TransformerItem* transformerItem = dynamic_cast<TransformerItem*>(item);
329 if (transformerItem)
330 return transformerItem->transformer;
331 return NULL;
334 // #pragma mark -
336 // TransformerAdded
337 void
338 TransformerListView::TransformerAdded(Transformer* transformer, int32 index)
340 // NOTE: we are in the thread that messed with the
341 // Shape, so no need to lock the document, when this is
342 // changed to asynchronous notifications, then it would
343 // need to be read-locked!
344 if (!LockLooper())
345 return;
347 _AddTransformer(transformer, index);
349 UnlockLooper();
352 // TransformerRemoved
353 void
354 TransformerListView::TransformerRemoved(Transformer* transformer)
356 // NOTE: we are in the thread that messed with the
357 // Shape, so no need to lock the document, when this is
358 // changed to asynchronous notifications, then it would
359 // need to be read-locked!
360 if (!LockLooper())
361 return;
363 _RemoveTransformer(transformer);
365 UnlockLooper();
368 // StyleChanged
369 void
370 TransformerListView::StyleChanged(Style* oldStyle, Style* newStyle)
372 // we don't care
375 // #pragma mark -
377 // SetMenu
378 void
379 TransformerListView::SetMenu(BMenu* menu)
381 if (fMenu == menu)
382 return;
384 fMenu = menu;
385 if (fMenu == NULL)
386 return;
388 BMenu* addMenu = new BMenu(B_TRANSLATE("Add"));
389 int32 cookie = 0;
390 uint32 type;
391 BString name;
392 while (TransformerFactory::NextType(&cookie, &type, &name)) {
393 // TODO: Disable the "Transformation" and "Perspective" transformers
394 // since they are not very useful or even implemented at all.
395 if (name == B_TRANSLATE("Transformation")
396 || name == B_TRANSLATE("Perspective"))
397 continue;
398 // End of TODO.
399 BMessage* message = new BMessage(MSG_ADD_TRANSFORMER);
400 message->AddInt32("type", type);
401 addMenu->AddItem(new BMenuItem(name.String(), message));
403 addMenu->SetTargetForItems(this);
404 fMenu->AddItem(addMenu);
406 _UpdateMenu();
409 // SetShape
410 void
411 TransformerListView::SetShape(Shape* shape)
413 if (fShape == shape)
414 return;
416 // detach from old container
417 if (fShape)
418 fShape->RemoveListener(this);
420 _MakeEmpty();
422 fShape = shape;
424 if (fShape) {
425 fShape->AddListener(this);
427 int32 count = fShape->CountTransformers();
428 for (int32 i = 0; i < count; i++)
429 _AddTransformer(fShape->TransformerAtFast(i), i);
432 _UpdateMenu();
435 // SetCommandStack
436 void
437 TransformerListView::SetCommandStack(CommandStack* stack)
439 fCommandStack = stack;
442 // #pragma mark -
444 // _AddTransformer
445 bool
446 TransformerListView::_AddTransformer(Transformer* transformer, int32 index)
448 if (transformer)
449 return AddItem(new TransformerItem(transformer, this), index);
450 return false;
453 // _RemoveTransformer
454 bool
455 TransformerListView::_RemoveTransformer(Transformer* transformer)
457 TransformerItem* item = _ItemForTransformer(transformer);
458 if (item && RemoveItem(item)) {
459 delete item;
460 return true;
462 return false;
465 // _ItemForTransformer
466 TransformerItem*
467 TransformerListView::_ItemForTransformer(Transformer* transformer) const
469 for (int32 i = 0;
470 TransformerItem* item = dynamic_cast<TransformerItem*>(ItemAt(i));
471 i++) {
472 if (item->transformer == transformer)
473 return item;
475 return NULL;
478 // _UpdateMenu
479 void
480 TransformerListView::_UpdateMenu()
482 fMenu->SetEnabled(fShape != NULL);