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