xref: /haiku/src/apps/cortex/RouteApp/RouteWindow.cpp (revision 68ea01249e1e2088933cb12f9c28d4e5c5d1c9ef)
1 /*
2  * Copyright (c) 1999-2000, Eric Moon.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions, and the following disclaimer.
11  *
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions, and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * 3. The name of the author may not be used to endorse or promote products
17  *    derived from this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
20  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21  * OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
23  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
26  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
27  * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30 
31 
32 // RouteWindow.cpp
33 // e.moon 14may99
34 
35 #include "RouteApp.h"
36 #include "RouteWindow.h"
37 #include "MediaRoutingView.h"
38 #include "StatusView.h"
39 
40 #include "DormantNodeWindow.h"
41 #include "TransportWindow.h"
42 
43 #include "RouteAppNodeManager.h"
44 #include "NodeGroup.h"
45 #include "TipManager.h"
46 
47 #include <Alert.h>
48 #include <Autolock.h>
49 #include <Debug.h>
50 #include <Font.h>
51 #include <MenuBar.h>
52 #include <Menu.h>
53 #include <MenuItem.h>
54 #include <Message.h>
55 #include <Messenger.h>
56 #include <Roster.h>
57 #include <Screen.h>
58 #include <ScrollView.h>
59 #include <StringView.h>
60 
61 #include <algorithm>
62 
63 #define D_HOOK(x) //PRINT (x)
64 #define D_INTERNAL(x) //PRINT (x)
65 
66 __USE_CORTEX_NAMESPACE
67 
68 
69 const char* const RouteWindow::s_windowName = "Cortex";
70 
71 const BRect RouteWindow::s_initFrame(100,100,700,550);
72 
73 const char* const g_aboutText =
74 	"Cortex/Route 2.1.2\n\n"
75 	"Copyright 1999-2000 Eric Moon\n"
76 	"All rights reserved.\n\n"
77 	"The Cortex Team:\n\n"
78 	"Christopher Lenz: UI\n"
79 	"Eric Moon: UI, back-end\n\n"
80 	"Thanks to:\nJohn Ashmun\nJon Watte\nDoug Wright\n<your name here>\n\n"
81 	"Certain icons used herein are the property of\n"
82 	"Be, Inc. and are used by permission.";
83 
84 
85 RouteWindow::~RouteWindow()
86 {
87 }
88 
89 
90 RouteWindow::RouteWindow(RouteAppNodeManager* manager)
91 	:
92 	BWindow(s_initFrame, s_windowName, B_DOCUMENT_WINDOW, 0),
93 	m_hScrollBar(0),
94 	m_vScrollBar(0),
95 	m_transportWindow(0),
96 	m_dormantNodeWindow(0),
97 	m_selectedGroupID(0),
98 	m_zoomed(false),
99 	m_zooming(false)
100 {
101 	BRect b = Bounds();
102 
103 	// initialize the menu bar: add all menus that target this window
104 	BMenuBar* pMenuBar = new BMenuBar(b, "menuBar");
105 	BMenu* pFileMenu = new BMenu("File");
106 	BMenuItem* item = new BMenuItem("Open" B_UTF8_ELLIPSIS,
107 		new BMessage(RouteApp::M_SHOW_OPEN_PANEL), 'O');
108 	item->SetTarget(be_app);
109 	pFileMenu->AddItem(item);
110 	pFileMenu->AddItem(new BSeparatorItem());
111 	item = new BMenuItem("Save nodes" B_UTF8_ELLIPSIS,
112 		new BMessage(RouteApp::M_SHOW_SAVE_PANEL), 'S');
113 	item->SetTarget(be_app);
114 	pFileMenu->AddItem(item);
115 	pFileMenu->AddItem(new BSeparatorItem());
116 	pFileMenu->AddItem(new BMenuItem("About Cortex/Route" B_UTF8_ELLIPSIS,
117 		new BMessage(B_ABOUT_REQUESTED)));
118 	pFileMenu->AddItem(new BSeparatorItem());
119 	pFileMenu->AddItem(new BMenuItem("Quit", new BMessage(B_QUIT_REQUESTED)));
120 	pMenuBar->AddItem(pFileMenu);
121 	AddChild(pMenuBar);
122 
123 	// build the routing view
124 	BRect rvBounds = b;
125 	rvBounds.top = pMenuBar->Frame().bottom+1;
126 	rvBounds.right -= B_V_SCROLL_BAR_WIDTH;
127 	rvBounds.bottom -= B_H_SCROLL_BAR_HEIGHT;
128 	m_routingView = new MediaRoutingView(manager, rvBounds, "routingView");
129 
130 	BRect hsBounds = rvBounds;
131 	hsBounds.left = rvBounds.left + 199;
132 	hsBounds.top = hsBounds.bottom + 1;
133 	hsBounds.right++;
134 	hsBounds.bottom = b.bottom + 1;
135 
136 	m_hScrollBar = new BScrollBar(hsBounds, "hScrollBar", m_routingView,
137 		0, 0, B_HORIZONTAL);
138 	AddChild(m_hScrollBar);
139 
140 	BRect vsBounds = rvBounds;
141 	vsBounds.left = vsBounds.right + 1;
142 	vsBounds.top--;
143 	vsBounds.right = b.right + 1;
144 	vsBounds.bottom++;
145 
146 	m_vScrollBar = new BScrollBar(vsBounds, "vScrollBar", m_routingView,
147 		0, 0, B_VERTICAL);
148 	AddChild(m_vScrollBar);
149 
150 	BRect svBounds = rvBounds;
151 	svBounds.left -= 1;
152 	svBounds.right = hsBounds.left - 1;
153 	svBounds.top = svBounds.bottom + 1;
154 	svBounds.bottom = b.bottom + 1;
155 
156 	m_statusView = new StatusView(svBounds, manager, m_hScrollBar);
157 	AddChild(m_statusView);
158 
159 	AddChild(m_routingView);
160 
161 	float minWidth, maxWidth, minHeight, maxHeight;
162 	GetSizeLimits(&minWidth, &maxWidth, &minHeight, &maxHeight);
163 	minWidth = m_statusView->Frame().Width() + 6 * B_V_SCROLL_BAR_WIDTH;
164 	minHeight = 6 * B_H_SCROLL_BAR_HEIGHT;
165 	SetSizeLimits(minWidth, maxWidth, minHeight, maxHeight);
166 
167 	// construct the Window menu
168 	BMenu* windowMenu = new BMenu("Window");
169 	m_transportWindowItem = new BMenuItem(
170 		"Show transport",
171 		new BMessage(M_TOGGLE_TRANSPORT_WINDOW));
172 	windowMenu->AddItem(m_transportWindowItem);
173 
174 	m_dormantNodeWindowItem = new BMenuItem(
175 		"Show add-ons",
176 		new BMessage(M_TOGGLE_DORMANT_NODE_WINDOW));
177 	windowMenu->AddItem(m_dormantNodeWindowItem);
178 
179 	windowMenu->AddItem(new BSeparatorItem());
180 
181 	m_pullPalettesItem = new BMenuItem(
182 		"Pull palettes",
183 		new BMessage(M_TOGGLE_PULLING_PALETTES));
184 	windowMenu->AddItem(m_pullPalettesItem);
185 
186 	pMenuBar->AddItem(windowMenu);
187 
188 	// create the dormant-nodes palette
189 	_toggleDormantNodeWindow();
190 
191 	// display group inspector
192 	_toggleTransportWindow();
193 }
194 
195 
196 //	#pragma mark - operations
197 
198 
199 /*!	Enable/disable palette position-locking (when the main
200 	window is moved, all palettes follow).
201 */
202 bool
203 RouteWindow::isPullPalettes() const
204 {
205 	return m_pullPalettesItem->IsMarked();
206 }
207 
208 
209 void
210 RouteWindow::setPullPalettes(bool enabled)
211 {
212 	m_pullPalettesItem->SetMarked(enabled);
213 }
214 
215 
216 void
217 RouteWindow::constrainToScreen()
218 {
219 	BScreen screen(this);
220 
221 	const BRect sr = screen.Frame();
222 
223 	// [c.lenz 1mar2000] this should be handled by every window
224 	// itself. will probably change soon ;-)
225 	_constrainToScreen();
226 /*	// main window
227 	BRect r = Frame();
228 	BPoint offset(0.0, 0.0);
229 	if(r.left < 0.0)
230 		offset.x = -r.left;
231 	if(r.top < 0.0)
232 		offset.y = -r.top;
233 	if(r.left >= (sr.right - 20.0))
234 		offset.x -= (r.left - (sr.Width()/2));
235 	if(r.top >= (sr.bottom - 20.0))
236 		offset.y -= (r.top - (sr.Height()/2));
237 	if(offset.x != 0.0 || offset.y != 0.0) {
238 		setPullPalettes(false);
239 		MoveBy(offset.x, offset.y);
240 	}*/
241 
242 	// transport window
243 	BPoint offset = BPoint(0.0, 0.0);
244 	BRect r = (m_transportWindow) ?
245 			   m_transportWindow->Frame() :
246 			   m_transportWindowFrame;
247 	if(r.left < 0.0)
248 		offset.x = (sr.Width()*.75) - r.left;
249 	if(r.top < 0.0)
250 		offset.y = (sr.Height()*.25) - r.top;
251 	if(r.left >= (sr.right - 20.0))
252 		offset.x -= (r.left - (sr.Width()/2));
253 	if(r.top >= (sr.bottom - 20.0))
254 		offset.y -= (r.top - (sr.Height()/2));
255 
256 	if(offset.x != 0.0 || offset.y != 0.0) {
257 		if(m_transportWindow)
258 			m_transportWindow->MoveBy(offset.x, offset.y);
259 		else
260 			m_transportWindowFrame.OffsetBy(offset.x, offset.y);
261 	}
262 
263 	// addon palette
264 	offset = BPoint(0.0, 0.0);
265 	r = (m_dormantNodeWindow) ?
266 		m_dormantNodeWindow->Frame() :
267 		m_dormantNodeWindowFrame;
268 	if(r.left < 0.0)
269 		offset.x = (sr.Width()*.25) - r.left;
270 	if(r.top < 0.0)
271 		offset.y = (sr.Height()*.125) - r.top;
272 	if(r.left >= (sr.right - 20.0))
273 		offset.x -= (r.left - (sr.Width()/2));
274 	if(r.top >= (sr.bottom - 20.0))
275 		offset.y -= (r.top - (sr.Height()/2));
276 
277 	if(offset.x != 0.0 || offset.y != 0.0) {
278 		if(m_dormantNodeWindow)
279 			m_dormantNodeWindow->MoveBy(offset.x, offset.y);
280 		else
281 			m_dormantNodeWindowFrame.OffsetBy(offset.x, offset.y);
282 	}
283 
284 }
285 
286 
287 //	#pragma mark - BWindow implementation
288 
289 
290 void
291 RouteWindow::FrameMoved(BPoint point)
292 {
293 	// ignore notification if the window isn't yet visible
294 	if(IsHidden())
295 		return;
296 
297 	BPoint delta = point - m_lastFramePosition;
298 	m_lastFramePosition = point;
299 
300 
301 	if (m_pullPalettesItem->IsMarked())
302 		_movePalettesBy(delta.x, delta.y);
303 }
304 
305 
306 void
307 RouteWindow::FrameResized(float width, float height)
308 {
309 	D_HOOK(("RouteWindow::FrameResized()\n"));
310 
311 	if (!m_zooming) {
312 		m_zoomed = false;
313 	}
314 	else {
315 		m_zooming = false;
316 	}
317 }
318 
319 
320 bool
321 RouteWindow::QuitRequested()
322 {
323 	be_app->PostMessage(B_QUIT_REQUESTED);
324 	return false; // [e.moon 20oct99] app now quits window
325 }
326 
327 
328 void
329 RouteWindow::Zoom(BPoint origin, float width, float height)
330 {
331 	D_HOOK(("RouteWindow::Zoom()\n"));
332 
333 	m_zooming = true;
334 
335 	BScreen screen(this);
336 	if (!screen.Frame().Contains(Frame())) {
337 		m_zoomed = false;
338 	}
339 
340 	if (!m_zoomed) {
341 		// resize to the ideal size
342 		m_manualSize = Bounds();
343 		float width, height;
344 		m_routingView->GetPreferredSize(&width, &height);
345 		width += B_V_SCROLL_BAR_WIDTH;
346 		height += B_H_SCROLL_BAR_HEIGHT;
347 		if (KeyMenuBar()) {
348 			height += KeyMenuBar()->Frame().Height();
349 		}
350 		ResizeTo(width, height);
351 		_constrainToScreen();
352 		m_zoomed = true;
353 	}
354 	else {
355 		// resize to the most recent manual size
356 		ResizeTo(m_manualSize.Width(), m_manualSize.Height());
357 		m_zoomed = false;
358 	}
359 }
360 
361 
362 //	#pragma mark - BHandler implemenation
363 
364 
365 void
366 RouteWindow::MessageReceived(BMessage* pMsg)
367 {
368 //	PRINT((
369 //		"RouteWindow::MessageReceived()\n"));
370 //	pMsg->PrintToStream();
371 //
372 	switch (pMsg->what) {
373 		case B_ABOUT_REQUESTED:
374 		{
375 			BAlert* alert = new BAlert("About", g_aboutText, "OK");
376 			alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
377 			alert->Go();
378 			break;
379 		}
380 		case MediaRoutingView::M_GROUP_SELECTED:
381 			_handleGroupSelected(pMsg);
382 			break;
383 
384 		case MediaRoutingView::M_SHOW_ERROR_MESSAGE:
385 			_handleShowErrorMessage(pMsg);
386 			break;
387 
388 		case M_TOGGLE_TRANSPORT_WINDOW:
389 			_toggleTransportWindow();
390 			break;
391 
392 		case M_REFRESH_TRANSPORT_SETTINGS:
393 			_refreshTransportSettings(pMsg);
394 			break;
395 
396 		case M_TOGGLE_PULLING_PALETTES:
397 			_togglePullPalettes();
398 			break;
399 
400 		case M_TOGGLE_DORMANT_NODE_WINDOW:
401 			_toggleDormantNodeWindow();
402 			break;
403 
404 		case M_TOGGLE_GROUP_ROLLING:
405 			_toggleGroupRolling();
406 			break;
407 
408 		default:
409 			_inherited::MessageReceived(pMsg);
410 			break;
411 	}
412 }
413 
414 
415 //	#pragma mark - IStateArchivable
416 
417 
418 status_t
419 RouteWindow::importState(const BMessage* archive)
420 {
421 	status_t err;
422 
423 	// frame rect
424 	BRect r;
425 	err = archive->FindRect("frame", &r);
426 	if(err == B_OK) {
427 		MoveTo(r.LeftTop());
428 		ResizeTo(r.Width(), r.Height());
429 		m_lastFramePosition = r.LeftTop();
430 	}
431 
432 	// status view width
433 	int32 i;
434 	err = archive->FindInt32("statusViewWidth", &i);
435 	if (err == B_OK) {
436 		float diff = i - m_statusView->Bounds().IntegerWidth();
437 		m_statusView->ResizeBy(diff, 0.0);
438 		m_hScrollBar->ResizeBy(-diff, 0.0);
439 		m_hScrollBar->MoveBy(diff, 0.0);
440 	}
441 
442 	// settings
443 	bool b;
444 	err = archive->FindBool("pullPalettes", &b);
445 	if(err == B_OK)
446 		m_pullPalettesItem->SetMarked(b);
447 
448 //	const char* p;
449 //	err = archive->FindString("saveDir", &p);
450 //	if(err == B_OK) {
451 //		m_openPanel.SetPanelDirectory(p);
452 //		m_savePanel.SetPanelDirectory(p);
453 //	}
454 //
455 	// dormant-node window
456 	err = archive->FindRect("addonPaletteFrame", &r);
457 	if (err == B_OK)
458 		m_dormantNodeWindowFrame = r;
459 	err = archive->FindBool("addonPaletteVisible", &b);
460 	if (err == B_OK && (b != (m_dormantNodeWindow != 0))) {
461 		_toggleDormantNodeWindow();
462 		if(!m_dormantNodeWindow)
463 			m_dormantNodeWindowFrame = r;
464 	}
465 
466 	if (m_dormantNodeWindow) {
467 		m_dormantNodeWindow->MoveTo(m_dormantNodeWindowFrame.LeftTop());
468 		m_dormantNodeWindow->ResizeTo(
469 			m_dormantNodeWindowFrame.Width(),
470 			m_dormantNodeWindowFrame.Height());
471 	}
472 
473 	// transport window
474 	err = archive->FindRect("transportFrame", &r);
475 	if (err == B_OK)
476 		m_transportWindowFrame = r;
477 	err = archive->FindBool("transportVisible", &b);
478 	if (err == B_OK && (b != (m_transportWindow != 0))) {
479 		_toggleTransportWindow();
480 		if (!m_transportWindow)
481 			m_transportWindowFrame = r;
482 	}
483 
484 	if (m_transportWindow) {
485 		m_transportWindow->MoveTo(m_transportWindowFrame.LeftTop());
486 		m_transportWindow->ResizeTo(
487 			m_transportWindowFrame.Width(),
488 			m_transportWindowFrame.Height());
489 	}
490 
491 	return B_OK;
492 }
493 
494 
495 status_t
496 RouteWindow::exportState(BMessage* archive) const
497 {
498 	BRect r = Frame();
499 	archive->AddRect("frame", r);
500 	archive->AddBool("pullPalettes", m_pullPalettesItem->IsMarked());
501 
502 	bool b = (m_dormantNodeWindow != 0);
503 	r = b ? m_dormantNodeWindow->Frame() : m_dormantNodeWindowFrame;
504 	archive->AddRect("addonPaletteFrame", r);
505 	archive->AddBool("addonPaletteVisible", b);
506 
507 	b = (m_transportWindow != 0);
508 	r = b ? m_transportWindow->Frame() : m_transportWindowFrame;
509 
510 	archive->AddRect("transportFrame", r);
511 	archive->AddBool("transportVisible", b);
512 
513 	// [c.lenz 23may00] remember status view width
514 	int i = m_statusView->Bounds().IntegerWidth();
515 	archive->AddInt32("statusViewWidth", i);
516 
517 //	entry_ref saveRef;
518 //	m_savePanel.GetPanelDirectory(&saveRef);
519 //	BEntry saveEntry(&saveRef);
520 //	if(saveEntry.InitCheck() == B_OK) {
521 //		BPath p;
522 //		saveEntry.GetPath(&p);
523 //		archive->AddString("saveDir", p.Path());
524 //	}
525 
526 	return B_OK;
527 }
528 
529 
530 //	#pragma mark - implementation
531 
532 
533 void
534 RouteWindow::_constrainToScreen()
535 {
536 	D_INTERNAL(("RouteWindow::_constrainToScreen()\n"));
537 
538 	BScreen screen(this);
539 	BRect screenRect = screen.Frame();
540 	BRect windowRect = Frame();
541 
542 	// if the window is outside the screen rect
543 	// move it to the default position
544 	if (!screenRect.Intersects(windowRect)) {
545 		windowRect.OffsetTo(screenRect.LeftTop());
546 		MoveTo(windowRect.LeftTop());
547 		windowRect = Frame();
548 	}
549 
550 	// if the window is larger than the screen rect
551 	// resize it to fit at each side
552 	if (!screenRect.Contains(windowRect)) {
553 		if (windowRect.left < screenRect.left) {
554 			windowRect.left = screenRect.left + 5.0;
555 			MoveTo(windowRect.LeftTop());
556 			windowRect = Frame();
557 		}
558 		if (windowRect.top < screenRect.top) {
559 			windowRect.top = screenRect.top + 5.0;
560 			MoveTo(windowRect.LeftTop());
561 			windowRect = Frame();
562 		}
563 		if (windowRect.right > screenRect.right) {
564 			windowRect.right = screenRect.right - 5.0;
565 		}
566 		if (windowRect.bottom > screenRect.bottom) {
567 			windowRect.bottom = screenRect.bottom - 5.0;
568 		}
569 		ResizeTo(windowRect.Width(), windowRect.Height());
570 	}
571 }
572 
573 
574 void
575 RouteWindow::_toggleTransportWindow()
576 {
577 	if (m_transportWindow) {
578 		m_transportWindowFrame = m_transportWindow->Frame();
579 		m_transportWindow->Lock();
580 		m_transportWindow->Quit();
581 		m_transportWindow = 0;
582 		m_transportWindowItem->SetMarked(false);
583 	} else {
584 		m_transportWindow = new TransportWindow(m_routingView->manager,
585 			this, "Transport");
586 
587 		// ask for a selection update
588 		BMessenger(m_routingView).SendMessage(
589 			MediaRoutingView::M_BROADCAST_SELECTION);
590 
591 		// place & display the window
592 		if (m_transportWindowFrame.IsValid()) {
593 			m_transportWindow->MoveTo(m_transportWindowFrame.LeftTop());
594 			m_transportWindow->ResizeTo(m_transportWindowFrame.Width(),
595 				m_transportWindowFrame.Height());
596 		}
597 
598 		m_transportWindow->Show();
599 		m_transportWindowItem->SetMarked(true);
600 	}
601 }
602 
603 
604 void
605 RouteWindow::_togglePullPalettes()
606 {
607 	m_pullPalettesItem->SetMarked(!m_pullPalettesItem->IsMarked());
608 }
609 
610 
611 void
612 RouteWindow::_toggleDormantNodeWindow()
613 {
614 	if (m_dormantNodeWindow) {
615 		m_dormantNodeWindowFrame = m_dormantNodeWindow->Frame();
616 		m_dormantNodeWindow->Lock();
617 		m_dormantNodeWindow->Quit();
618 		m_dormantNodeWindow = 0;
619 		m_dormantNodeWindowItem->SetMarked(false);
620 	} else {
621 		m_dormantNodeWindow = new DormantNodeWindow(this);
622 		if (m_dormantNodeWindowFrame.IsValid()) {
623 			m_dormantNodeWindow->MoveTo(m_dormantNodeWindowFrame.LeftTop());
624 			m_dormantNodeWindow->ResizeTo(m_dormantNodeWindowFrame.Width(),
625 				m_dormantNodeWindowFrame.Height());
626 		}
627 		m_dormantNodeWindow->Show();
628 		m_dormantNodeWindowItem->SetMarked(true);
629 	}
630 }
631 
632 
633 void
634 RouteWindow::_handleGroupSelected(BMessage* message)
635 {
636 	status_t err;
637 	uint32 groupID;
638 
639 	err = message->FindInt32("groupID", (int32*)&groupID);
640 	if (err < B_OK) {
641 		PRINT((
642 			"! RouteWindow::_handleGroupSelected(): no groupID in message!\n"));
643 		return;
644 	}
645 
646 	if (!m_transportWindow)
647 		return;
648 
649 	BMessage m(TransportWindow::M_SELECT_GROUP);
650 	m.AddInt32("groupID", groupID);
651 	BMessenger(m_transportWindow).SendMessage(&m);
652 
653 	m_selectedGroupID = groupID;
654 }
655 
656 
657 void
658 RouteWindow::_handleShowErrorMessage(BMessage* message)
659 {
660 	status_t err;
661 	BString text;
662 
663 	err = message->FindString("text", &text);
664 	if (err < B_OK) {
665 		PRINT((
666 			"! RouteWindow::_handleShowErrorMessage(): no text in message!\n"));
667 		return;
668 	}
669 
670 	m_statusView->setErrorMessage(text.String(), message->HasBool("error"));
671 }
672 
673 
674 //! Refresh the transport window for the given group, if any
675 void
676 RouteWindow::_refreshTransportSettings(BMessage* message)
677 {
678 	status_t err;
679 	uint32 groupID;
680 
681 	err = message->FindInt32("groupID", (int32*)&groupID);
682 	if (err < B_OK) {
683 		PRINT((
684 			"! RouteWindow::_refreshTransportSettings(): no groupID in message!\n"));
685 		return;
686 	}
687 
688 	if(m_transportWindow) {
689 		// relay the message
690 		BMessenger(m_transportWindow).SendMessage(message);
691 	}
692 }
693 
694 
695 void
696 RouteWindow::_closePalettes()
697 {
698 	BAutolock _l(this);
699 
700 	if (m_transportWindow) {
701 		m_transportWindow->Lock();
702 		m_transportWindow->Quit();
703 		m_transportWindow = 0;
704 	}
705 }
706 
707 
708 //!	Move all palette windows by the specified amounts
709 void RouteWindow::_movePalettesBy(float xDelta, float yDelta)
710 {
711 	if (m_transportWindow)
712 		m_transportWindow->MoveBy(xDelta, yDelta);
713 
714 	if (m_dormantNodeWindow)
715 		m_dormantNodeWindow->MoveBy(xDelta, yDelta);
716 }
717 
718 
719 //!	Toggle group playback
720 void
721 RouteWindow::_toggleGroupRolling()
722 {
723 	if (!m_selectedGroupID)
724 		return;
725 
726 	NodeGroup* g;
727 	status_t err = m_routingView->manager->findGroup(m_selectedGroupID, &g);
728 	if (err < B_OK)
729 		return;
730 
731 	Autolock _l(g);
732 	uint32 startAction = (g->runMode() == BMediaNode::B_OFFLINE)
733 		? NodeGroup::M_ROLL : NodeGroup::M_START;
734 
735 	BMessenger m(g);
736 	switch (g->transportState()) {
737 		case NodeGroup::TRANSPORT_STOPPED:
738 			m.SendMessage(startAction);
739 			break;
740 
741 		case NodeGroup::TRANSPORT_RUNNING:
742 		case NodeGroup::TRANSPORT_ROLLING:
743 			m.SendMessage(NodeGroup::M_STOP);
744 			break;
745 
746 		default:
747 			break;
748 	}
749 }
750