1/*
2 * Copyright 2016-2017, Rene Gollent, rene@gollent.com.
3 * Distributed under the terms of the MIT License.
4 */
5#include "ConnectionConfigWindow.h"
6
7#include <Application.h>
8#include <Button.h>
9#include <GroupView.h>
10#include <MenuField.h>
11#include <LayoutBuilder.h>
12
13#include <AutoDeleter.h>
14#include <AutoLocker.h>
15
16#include "AppMessageCodes.h"
17#include "ConnectionConfigHandlerRoster.h"
18#include "Settings.h"
19#include "TargetHostInterfaceInfo.h"
20#include "TargetHostInterfaceRoster.h"
21#include "TargetHostInterface.h"
22
23
24enum {
25	MSG_SWITCH_CONNECTION_TYPE 	= 'swct',
26	MSG_CREATE_CONNECTION 		= 'crco'
27};
28
29
30ConnectionConfigWindow::ConnectionConfigWindow()
31	:
32	BWindow(BRect(), "Create new connection", B_TITLED_WINDOW,
33		B_AUTO_UPDATE_SIZE_LIMITS | B_CLOSE_ON_ESCAPE),
34	ConnectionConfigView::Listener(),
35	fConnectionTypeField(NULL),
36	fConfigGroupView(NULL),
37	fCloseButton(NULL),
38	fConnectButton(NULL),
39	fCurrentSettings(NULL),
40	fActiveInfo(NULL)
41{
42}
43
44
45ConnectionConfigWindow::~ConnectionConfigWindow()
46{
47	if (fCurrentSettings != NULL)
48		fCurrentSettings->ReleaseReference();
49}
50
51
52ConnectionConfigWindow*
53ConnectionConfigWindow::Create()
54{
55	ConnectionConfigWindow* self = new ConnectionConfigWindow();
56
57	try {
58		self->_Init();
59	} catch (...) {
60		delete self;
61		throw;
62	}
63
64	return self;
65
66}
67
68
69void
70ConnectionConfigWindow::Show()
71{
72	CenterOnScreen();
73	BWindow::Show();
74}
75
76
77bool
78ConnectionConfigWindow::QuitRequested()
79{
80	return be_app_messenger.SendMessage(MSG_CONNECTION_CONFIG_WINDOW_CLOSED)
81		== B_OK;
82}
83
84
85void
86ConnectionConfigWindow::ConfigurationChanged(Settings* settings)
87{
88	if (fCurrentSettings != NULL)
89		fCurrentSettings->ReleaseReference();
90	fCurrentSettings = settings;
91	fCurrentSettings->AcquireReference();
92
93	fConnectButton->SetEnabled(fActiveInfo->IsConfigured(settings));
94}
95
96
97void
98ConnectionConfigWindow::MessageReceived(BMessage* message)
99{
100	switch (message->what) {
101		case MSG_CREATE_CONNECTION:
102		{
103			TargetHostInterfaceRoster* roster
104				= TargetHostInterfaceRoster::Default();
105			AutoLocker<TargetHostInterfaceRoster> rosterLocker(roster);
106
107			TargetHostInterface* interface;
108			status_t error = roster->CreateInterface(fActiveInfo,
109				fCurrentSettings, interface);
110
111			// TODO: notify user.
112			if (error != B_OK)
113				break;
114
115			PostMessage(B_QUIT_REQUESTED);
116			break;
117		}
118		default:
119			BWindow::MessageReceived(message);
120			break;
121	}
122}
123
124
125void
126ConnectionConfigWindow::_Init()
127{
128	BMenu* menu = _BuildTypeMenu();
129
130	fConfigGroupView = new BGroupView(B_HORIZONTAL);
131
132	BLayoutBuilder::Group<>(this, B_VERTICAL)
133		.SetInsets(B_USE_DEFAULT_SPACING)
134		.Add(fConnectionTypeField = new BMenuField("Type:", menu))
135		.AddGroup(fConfigGroupView)
136			// this group is a placeholder to contain
137			// the actual config view
138		.End()
139		.AddGroup(B_HORIZONTAL)
140			.SetInsets(B_USE_SMALL_SPACING)
141			.AddGlue()
142			.Add(fCloseButton = new BButton("Close",
143					new BMessage(B_QUIT_REQUESTED)))
144			.Add(fConnectButton = new BButton("Connect",
145					new BMessage(MSG_CREATE_CONNECTION)))
146		.End();
147
148	fConnectionTypeField->Menu()->SetLabelFromMarked(true);
149	fConnectionTypeField->Menu()->SetTargetForItems(this);
150
151	fCloseButton->SetTarget(this);
152	fConnectButton->SetTarget(this);
153	fConnectButton->SetEnabled(false);
154
155	if (menu->CountItems() > 0) {
156		BMenuItem* item = menu->ItemAt(0);
157		BMessage* message = item->Message();
158		TargetHostInterfaceInfo* info = NULL;
159		if (message->FindPointer("info", reinterpret_cast<void**>(&info))
160			== B_OK) {
161			_UpdateActiveConfig(info);
162			menu->ItemAt(0)->SetMarked(true);
163		}
164	}
165}
166
167
168BMenu*
169ConnectionConfigWindow::_BuildTypeMenu()
170{
171	BMenu* menu = new BMenu("Types");
172	TargetHostInterfaceRoster* roster = TargetHostInterfaceRoster::Default();
173
174	AutoLocker<TargetHostInterfaceRoster> rosterLocker(roster);
175
176	for (int32 i = 0; i < roster->CountInterfaceInfos(); i++) {
177		TargetHostInterfaceInfo* info = roster->InterfaceInfoAt(i);
178		if (info->IsLocal())
179			continue;
180
181		BMenuItem* item = new BMenuItem(info->Name(), new BMessage(
182				MSG_SWITCH_CONNECTION_TYPE));
183		item->Message()->AddPointer("info", info);
184		menu->AddItem(item);
185	}
186
187	return menu;
188}
189
190
191void
192ConnectionConfigWindow::_UpdateActiveConfig(TargetHostInterfaceInfo* info)
193{
194	if (fConfigGroupView->CountChildren() > 0) {
195		BView* view = fConfigGroupView->ChildAt(0);
196		fConfigGroupView->RemoveChild(view);
197		delete view;
198	}
199
200	ConnectionConfigHandlerRoster* roster
201		= ConnectionConfigHandlerRoster::Default();
202
203	if (roster->HasHandlerFor(info)) {
204		ConnectionConfigView* view = NULL;
205		status_t error = roster->CreateConfigView(info, this, view);
206		if (error != B_OK)
207			return;
208
209		ObjectDeleter<ConnectionConfigView> viewDeleter(view);
210		BLayoutItem* item = fConfigGroupView->GroupLayout()->AddView(view);
211		if (item != NULL)
212			viewDeleter.Detach();
213
214		fActiveInfo = info;
215	}
216
217	fConfigGroupView->InvalidateLayout();
218}
219