1/*
2 * Copyright 2008-2013 Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT license.
4 *
5 * Authors:
6 *		Stephan Aßmus <superstippi@gmx.de>
7 *		Axel Dörfler, axeld@pinc-software.de.
8 *		Karsten Heimrich. <host.haiku@gmx.de>
9 */
10
11
12#include "AbstractParametersPanel.h"
13
14#include <driver_settings.h>
15#include <stdio.h>
16
17#include <Button.h>
18#include <Catalog.h>
19#include <DiskSystemAddOn.h>
20#include <DiskSystemAddOnManager.h>
21#include <GroupLayout.h>
22#include <MessageFilter.h>
23#include <String.h>
24
25
26#undef B_TRANSLATION_CONTEXT
27#define B_TRANSLATION_CONTEXT "AbstractParametersPanel"
28
29
30static const uint32 kMsgOk = 'okok';
31static const uint32 kParameterChanged = 'pmch';
32
33
34class AbstractParametersPanel::EscapeFilter : public BMessageFilter {
35public:
36	EscapeFilter(AbstractParametersPanel* target)
37		:
38		BMessageFilter(B_ANY_DELIVERY, B_ANY_SOURCE),
39		fPanel(target)
40	{
41	}
42
43	virtual	~EscapeFilter()
44	{
45	}
46
47	virtual filter_result Filter(BMessage* message, BHandler** target)
48	{
49		filter_result result = B_DISPATCH_MESSAGE;
50		switch (message->what) {
51			case B_KEY_DOWN:
52			case B_UNMAPPED_KEY_DOWN: {
53				uint32 key;
54				if (message->FindInt32("raw_char", (int32*)&key) >= B_OK) {
55					if (key == B_ESCAPE) {
56						result = B_SKIP_MESSAGE;
57						fPanel->Cancel();
58					}
59				}
60				break;
61			}
62			default:
63				break;
64		}
65		return result;
66	}
67
68private:
69 	AbstractParametersPanel*	fPanel;
70};
71
72
73// #pragma mark -
74
75
76AbstractParametersPanel::AbstractParametersPanel(BWindow* window)
77	:
78	BWindow(BRect(300.0, 200.0, 600.0, 300.0), 0, B_MODAL_WINDOW_LOOK,
79		B_MODAL_SUBSET_WINDOW_FEEL,
80		B_ASYNCHRONOUS_CONTROLS | B_AUTO_UPDATE_SIZE_LIMITS),
81	fOkButton(new BButton(B_TRANSLATE("OK"), new BMessage(kMsgOk))),
82	fReturnStatus(B_CANCELED),
83	fEditor(NULL),
84	fEscapeFilter(new EscapeFilter(this)),
85	fExitSemaphore(create_sem(0, "AbstractParametersPanel exit")),
86	fWindow(window)
87{
88	AddCommonFilter(fEscapeFilter);
89	AddToSubset(fWindow);
90}
91
92
93AbstractParametersPanel::~AbstractParametersPanel()
94{
95	RemoveCommonFilter(fEscapeFilter);
96	delete fEscapeFilter;
97
98	delete_sem(fExitSemaphore);
99
100	if (fEditor == NULL)
101		delete fOkButton;
102}
103
104
105bool
106AbstractParametersPanel::QuitRequested()
107{
108	release_sem(fExitSemaphore);
109	return false;
110}
111
112
113void
114AbstractParametersPanel::MessageReceived(BMessage* message)
115{
116	switch (message->what) {
117		case B_CANCEL:
118			Cancel();
119			break;
120
121		case kMsgOk:
122			fReturnStatus = B_OK;
123			release_sem(fExitSemaphore);
124			break;
125
126		case kParameterChanged:
127			fOkButton->SetEnabled(fEditor->ValidateParameters());
128			break;
129
130		default:
131			BWindow::MessageReceived(message);
132	}
133}
134
135
136status_t
137AbstractParametersPanel::Go(BString& parameters)
138{
139	// Without an editor, we cannot change anything, anyway
140	if (fEditor == NULL) {
141		parameters = "";
142		if (fReturnStatus == B_CANCELED)
143			fReturnStatus = B_OK;
144
145		if (!Lock())
146			return B_ERROR;
147	} else {
148		// run the window thread, to get an initial layout of the controls
149		Hide();
150		Show();
151		if (!Lock())
152			return B_CANCELED;
153
154		// center the panel above the parent window
155		CenterIn(fWindow->Frame());
156
157		Show();
158		Unlock();
159
160		// block this thread now, but keep the window repainting
161		while (true) {
162			status_t status = acquire_sem_etc(fExitSemaphore, 1,
163				B_CAN_INTERRUPT | B_RELATIVE_TIMEOUT, 50000);
164			if (status != B_TIMED_OUT && status != B_INTERRUPTED)
165				break;
166			fWindow->UpdateIfNeeded();
167		}
168
169		if (!Lock())
170			return B_CANCELED;
171
172		if (fReturnStatus == B_OK) {
173			if (fEditor->ValidateParameters()) {
174				status_t err = fEditor->GetParameters(parameters);
175				if (err != B_OK)
176					fReturnStatus = err;
177			}
178		}
179	}
180
181	status_t status = fReturnStatus;
182
183	Quit();
184		// NOTE: this object is toast now!
185
186	return status;
187}
188
189
190void
191AbstractParametersPanel::Cancel()
192{
193	fReturnStatus = B_CANCELED;
194	release_sem(fExitSemaphore);
195}
196
197
198void
199AbstractParametersPanel::Init(B_PARAMETER_EDITOR_TYPE type,
200	const BString& diskSystem, BPartition* partition)
201{
202	// Create partition parameter editor
203
204	status_t status = B_ERROR;
205	if (diskSystem.IsEmpty()) {
206		status = partition->GetParameterEditor(type, &fEditor);
207	} else {
208		DiskSystemAddOnManager* manager = DiskSystemAddOnManager::Default();
209		BDiskSystemAddOn* addOn = manager->GetAddOn(diskSystem);
210		if (addOn != NULL) {
211			// put the add-on
212			manager->PutAddOn(addOn);
213
214			status = addOn->GetParameterEditor(type, &fEditor);
215		}
216	}
217	if (status != B_OK && status != B_NOT_SUPPORTED)
218		fReturnStatus = status;
219
220	if (fEditor == NULL)
221		return;
222
223	// Create controls
224
225	BLayoutBuilder::Group<> builder = BLayoutBuilder::Group<>(this,
226		B_VERTICAL);
227	AddControls(builder, fEditor->View());
228
229	builder.AddGroup(B_HORIZONTAL, B_USE_DEFAULT_SPACING)
230			.AddGlue()
231			.Add(new BButton(B_TRANSLATE("Cancel"), new BMessage(B_CANCEL)))
232			.Add(fOkButton)
233		.End()
234		.SetInsets(B_USE_DEFAULT_SPACING);
235
236	SetDefaultButton(fOkButton);
237
238	fEditor->SetTo(partition);
239	fEditor->SetModificationMessage(new BMessage(kParameterChanged));
240}
241
242
243void
244AbstractParametersPanel::AddControls(BLayoutBuilder::Group<>& builder,
245	BView* editorView)
246{
247	builder.Add(editorView);
248}
249