/*
 * Copyright 2015-2016, Rene Gollent, rene@gollent.com.
 * Distributed under the terms of the MIT License.
 */
#include "SignalDispositionEditWindow.h"
 
#include <signal.h>
 
#include <Button.h>
#include <LayoutBuilder.h>
#include <MenuField.h>
 
#include <AutoDeleter.h>
#include <AutoLocker.h>
 
#include "AppMessageCodes.h"
#include "SignalDispositionMenu.h"
#include "SignalDispositionTypes.h"
#include "Team.h"
#include "UiUtils.h"
#include "UserInterface.h"
 
 
enum {
	MSG_SELECTED_SIGNAL_CHANGED 		= 'ssic',
	MSG_SELECTED_DISPOSITION_CHANGED 	= 'sdic',
	MSG_SAVE_SIGNAL_DISPOSITION 		= 'ssid'
};
 
 
SignalDispositionEditWindow::SignalDispositionEditWindow(::Team* team,
	int32 signal, UserInterfaceListener* listener, BHandler* target)
	:
	BWindow(BRect(), "Edit signal disposition", B_FLOATING_WINDOW,
		B_AUTO_UPDATE_SIZE_LIMITS | B_CLOSE_ON_ESCAPE),
	fTeam(team),
	fListener(listener),
	fEditMode(signal > 0),
	fCurrentSignal(signal),
	fSaveButton(NULL),
	fCancelButton(NULL),
	fSignalSelectionField(NULL),
	fDispositionSelectionField(NULL),
	fTarget(target)
{
}
 
 
SignalDispositionEditWindow::~SignalDispositionEditWindow()
{
	BMessenger(fTarget).SendMessage(MSG_SIGNAL_DISPOSITION_EDIT_WINDOW_CLOSED);
}
 
 
SignalDispositionEditWindow*
SignalDispositionEditWindow::Create(::Team* team, int32 signal,
	UserInterfaceListener* listener, BHandler* target)
{
	SignalDispositionEditWindow* self = new SignalDispositionEditWindow(
		team, signal, listener, target);
 
	try {
		self->_Init();
	} catch (...) {
		delete self;
		throw;
	}
 
	return self;
 
}
 
void
SignalDispositionEditWindow::MessageReceived(BMessage* message)
{
	switch (message->what) {
		case MSG_SELECTED_SIGNAL_CHANGED:
		{
			int32 signal;
			if (message->FindInt32("signal", &signal) == B_OK)
				fCurrentSignal = signal;
			break;
		}
		case MSG_SELECTED_DISPOSITION_CHANGED:
		{
			int32 disposition;
			if (message->FindInt32("disposition", &disposition) == B_OK)
				fCurrentDisposition = disposition;
			break;
		}
		case MSG_SAVE_SIGNAL_DISPOSITION:
		{
			fListener->SetCustomSignalDispositionRequested(fCurrentSignal,
				fCurrentDisposition);
			// fall through
		}
		case B_CANCEL:
			Quit();
			break;
 
		default:
			BWindow::MessageReceived(message);
			break;
	}
 
}
 
 
void
SignalDispositionEditWindow::Show()
{
	CenterOnScreen();
	BWindow::Show();
}
 
 
void
SignalDispositionEditWindow::_Init()
{
	SignalDispositionMenu* menu = new SignalDispositionMenu("dispositionMenu",
		new BMessage(MSG_SELECTED_DISPOSITION_CHANGED));
 
	BLayoutBuilder::Group<>(this, B_VERTICAL)
		.SetInsets(B_USE_DEFAULT_SPACING)
		.AddGroup(B_HORIZONTAL)
			.Add((fSignalSelectionField = new BMenuField("Signal:",
				_BuildSignalSelectionMenu())))
			.Add((fDispositionSelectionField = new BMenuField("Disposition:",
				menu)))
		.End()
		.AddGroup(B_HORIZONTAL)
			.AddGlue()
			.Add((fSaveButton = new BButton("Save",
				new BMessage(MSG_SAVE_SIGNAL_DISPOSITION))))
			.Add((fCancelButton = new BButton("Cancel",
				new BMessage(B_CANCEL))))
		.End()
	.End();
 
	fSignalSelectionField->Menu()->SetLabelFromMarked(true);
	fSignalSelectionField->Menu()->SetTargetForItems(this);
	menu->SetLabelFromMarked(true);
	menu->SetTargetForItems(this);
 
	AutoLocker< ::Team> teamLocker(fTeam);
	_UpdateState();
 
	// if we're editing an existing row, don't allow changing the signal
	// selection
	if (fEditMode)
		fSignalSelectionField->SetEnabled(false);
 
 
}
 
 
BMenu*
SignalDispositionEditWindow::_BuildSignalSelectionMenu()
{
	BMenu* menu = new BMenu("signals");
	BMenuItem* item;
 
	#undef ADD_SIGNAL_MENU_ITEM
	#define ADD_SIGNAL_MENU_ITEM(x)										\
		menu->AddItem((item = new BMenuItem(#x, new BMessage(			\
			MSG_SELECTED_SIGNAL_CHANGED))));							\
		item->Message()->AddInt32("signal", x);
 
	ADD_SIGNAL_MENU_ITEM(SIGHUP)
	ADD_SIGNAL_MENU_ITEM(SIGINT)
	ADD_SIGNAL_MENU_ITEM(SIGQUIT)
	ADD_SIGNAL_MENU_ITEM(SIGILL)
	ADD_SIGNAL_MENU_ITEM(SIGCHLD)
	ADD_SIGNAL_MENU_ITEM(SIGABRT)
	ADD_SIGNAL_MENU_ITEM(SIGPIPE)
	ADD_SIGNAL_MENU_ITEM(SIGFPE)
	ADD_SIGNAL_MENU_ITEM(SIGKILL)
	ADD_SIGNAL_MENU_ITEM(SIGSTOP)
	ADD_SIGNAL_MENU_ITEM(SIGSEGV)
	ADD_SIGNAL_MENU_ITEM(SIGCONT)
	ADD_SIGNAL_MENU_ITEM(SIGTSTP)
	ADD_SIGNAL_MENU_ITEM(SIGALRM)
	ADD_SIGNAL_MENU_ITEM(SIGTERM)
	ADD_SIGNAL_MENU_ITEM(SIGTTIN)
	ADD_SIGNAL_MENU_ITEM(SIGTTOU)
	ADD_SIGNAL_MENU_ITEM(SIGUSR1)
	ADD_SIGNAL_MENU_ITEM(SIGUSR2)
	ADD_SIGNAL_MENU_ITEM(SIGWINCH)
	ADD_SIGNAL_MENU_ITEM(SIGKILLTHR)
	ADD_SIGNAL_MENU_ITEM(SIGTRAP)
	ADD_SIGNAL_MENU_ITEM(SIGPOLL)
	ADD_SIGNAL_MENU_ITEM(SIGPROF)
	ADD_SIGNAL_MENU_ITEM(SIGSYS)
	ADD_SIGNAL_MENU_ITEM(SIGURG)
	ADD_SIGNAL_MENU_ITEM(SIGVTALRM)
	ADD_SIGNAL_MENU_ITEM(SIGXCPU)
	ADD_SIGNAL_MENU_ITEM(SIGXFSZ)
	ADD_SIGNAL_MENU_ITEM(SIGBUS)
 
	BString signalName;
	for (int32 i = SIGRTMIN; i <= SIGRTMAX; i++) {
		menu->AddItem((item = new BMenuItem(UiUtils::SignalNameToString(i,
					signalName), new BMessage(MSG_SELECTED_SIGNAL_CHANGED))));
		item->Message()->AddInt32("signal", i);
	}
 
	return menu;
}
 
 
void
SignalDispositionEditWindow::_UpdateState()
{
	if (fCurrentSignal <= 0)
		fCurrentSignal = SIGHUP;
 
	fSignalSelectionField->Menu()->ItemAt(fCurrentSignal - 1)->SetMarked(true);
 
	fCurrentDisposition = fTeam->SignalDispositionFor(fCurrentSignal);
	fDispositionSelectionField->Menu()->ItemAt(fCurrentDisposition)->SetMarked(
		true);
}
 

V730 Not all members of a class are initialized inside the constructor. Consider inspecting: fCurrentDisposition.