xref: /haiku/src/preferences/datatranslations/DataTranslationsWindow.cpp (revision a76f629efad0ba4d6518d918a39dbcc6097fe536)
1 /*
2  * Copyright 2002-2009, Haiku, Inc.
3  * Distributed under the terms of the MIT license.
4  *
5  * Authors:
6  *		Oliver Siebenmarck
7  *		Andrew McCall, mccall@digitalparadise.co.uk
8  *		Michael Wilber
9  *		Maxime Simon
10  */
11 
12 
13 #include "DataTranslations.h"
14 #include "DataTranslationsWindow.h"
15 #include "IconView.h"
16 #include "TranslatorListView.h"
17 
18 #include <Application.h>
19 #include <Screen.h>
20 #include <Alert.h>
21 #include <Bitmap.h>
22 #include <Box.h>
23 #include <Button.h>
24 #include <ListView.h>
25 #include <Path.h>
26 #include <ScrollView.h>
27 #include <String.h>
28 #include <StringView.h>
29 #include <TextView.h>
30 #include <TranslationDefs.h>
31 #include <TranslatorRoster.h>
32 
33 #include "Area.h"
34 #include "BALMLayout.h"
35 #include "OperatorType.h"
36 #include "XTab.h"
37 #include "YTab.h"
38 
39 #define DTW_RIGHT	400
40 #define DTW_BOTTOM	300
41 
42 
43 const uint32 kMsgTranslatorInfo = 'trin';
44 const uint32 kMsgSelectedTranslator = 'trsl';
45 
46 
47 DataTranslationsWindow::DataTranslationsWindow()
48 	: BWindow(BRect(0, 0, DTW_RIGHT, DTW_BOTTOM),
49 		"DataTranslations", B_TITLED_WINDOW,
50 		B_ASYNCHRONOUS_CONTROLS | B_NOT_ZOOMABLE | B_NOT_RESIZABLE | B_AUTO_UPDATE_SIZE_LIMITS)
51 {
52 	MoveTo(dynamic_cast<DataTranslationsApplication *>(be_app)->WindowCorner());
53 
54 	// Make sure that the window isn't positioned off screen
55 	BScreen screen;
56 	BRect scrf = screen.Frame(), winf = Frame();
57 	float x = winf.left, y = winf.top;
58 	scrf.top += 24;
59 	scrf.left += 5;
60 	scrf.right -= 5;
61 	if (winf.left < scrf.left)
62 		x = scrf.left;
63 	if (winf.right > scrf.right)
64 		x = scrf.right - winf.Width() - 5;
65 	if (winf.top < scrf.top)
66 		y = scrf.top;
67 	if (winf.bottom > scrf.bottom)
68 		y = scrf.bottom - winf.Height() - 15;
69 
70 	if (x != winf.left || y != winf.top)
71 		MoveTo(x, y);
72 
73 	_SetupViews();
74 
75 	BTranslatorRoster *roster = BTranslatorRoster::Default();
76 	roster->StartWatching(this);
77 
78 	Show();
79 }
80 
81 
82 DataTranslationsWindow::~DataTranslationsWindow()
83 {
84 	BTranslatorRoster *roster = BTranslatorRoster::Default();
85 	roster->StopWatching(this);
86 }
87 
88 
89 // Reads the installed translators and adds them to our BListView
90 status_t
91 DataTranslationsWindow::_PopulateListView()
92 {
93 	BTranslatorRoster *roster = BTranslatorRoster::Default();
94 
95 	// Get all Translators on the system. Gives us the number of translators
96 	// installed in num_translators and a reference to the first one
97 	int32 numTranslators;
98 	translator_id *translators = NULL;
99 	roster->GetAllTranslators(&translators, &numTranslators);
100 
101 	for (int32 i = 0; i < numTranslators; i++) {
102 		// Getting the first three Infos: Name, Info & Version
103 		int32 version;
104 		const char *name, *info;
105 		roster->GetTranslatorInfo(translators[i], &name, &info, &version);
106 		fTranslatorListView->AddItem(new TranslatorItem(translators[i], name));
107 	}
108 
109 	delete[] translators;
110 	return B_OK;
111 }
112 
113 
114 status_t
115 DataTranslationsWindow::_GetTranslatorInfo(int32 id, const char*& name,
116 	const char*& info, int32& version, BPath& path)
117 {
118 	// Returns information about the translator with the given id
119 
120 	if (id < 0)
121 		return B_BAD_VALUE;
122 
123 	BTranslatorRoster *roster = BTranslatorRoster::Default();
124 	if (roster->GetTranslatorInfo(id, &name, &info, &version) != B_OK)
125 		return B_ERROR;
126 
127 	// Get the translator's path
128 	entry_ref ref;
129 	if (roster->GetRefFor(id, &ref) == B_OK) {
130 		BEntry entry(&ref);
131 		path.SetTo(&entry);
132 	} else
133 		path.Unset();
134 
135 	return B_OK;
136 }
137 
138 
139 status_t
140 DataTranslationsWindow::_ShowConfigView(int32 id)
141 {
142 	// Shows the config panel for the translator with the given id
143 
144 	if (id < 0)
145 		return B_BAD_VALUE;
146 
147 	BTranslatorRoster *roster = BTranslatorRoster::Default();
148 
149 	// fConfigView is NULL the first time this function
150 	// is called, prevent a segment fault
151 	if (fConfigView)
152 		fRightBox->RemoveChild(fConfigView);
153 
154 	BMessage emptyMsg;
155 	BRect rect(0, 0, 200, 233);
156 	status_t ret = roster->MakeConfigurationView(id, &emptyMsg, &fConfigView, &rect);
157 	if (ret != B_OK) {
158 		fRightBox->RemoveChild(fConfigView);
159 		return ret;
160 	}
161 
162 	BRect configRect(fRightBox->Bounds());
163 	configRect.InsetBy(3, 3);
164 	configRect.bottom -= 45;
165 	float width = 0, height = 0;
166 	if ((fConfigView->Flags() & B_SUPPORTS_LAYOUT) != 0) {
167 		BSize configSize = fConfigView->ExplicitPreferredSize();
168 		width = configSize.Width();
169 		height = configSize.Height();
170 	} else {
171 		fConfigView->GetPreferredSize(&width, &height);
172 	}
173 	float widen = max_c(0, width - configRect.Width());
174 	float heighten = max_c(0, height - configRect.Height());
175 	if (widen > 0 || heighten > 0) {
176 		ResizeBy(widen, heighten);
177 		configRect.right += widen;
178 		configRect.bottom += heighten;
179 	}
180 	fConfigView->MoveTo(configRect.left, configRect.top);
181 	fConfigView->ResizeTo(configRect.Width(), configRect.Height());
182 	fConfigView->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
183 		// force config views to all have the same color
184 	fRightBox->AddChild(fConfigView);
185 
186 	return B_OK;
187 }
188 
189 
190 void
191 DataTranslationsWindow::_SetupViews()
192 {
193 	fConfigView = NULL;
194 	// This is NULL until a translator is
195 	// selected from the listview
196 
197 	// Window box
198 	BView* mainView = new BView(Bounds(), "", B_FOLLOW_ALL, B_WILL_DRAW | B_FRAME_EVENTS);
199 	mainView->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
200 	AddChild(mainView);
201 
202 	// Add the translators list view
203 	fTranslatorListView = new TranslatorListView(BRect(0, 0, 1, 1), "TransList",
204 		B_SINGLE_SELECTION_LIST);
205 	fTranslatorListView->SetSelectionMessage(new BMessage(kMsgSelectedTranslator));
206 
207 	BScrollView *scrollView = new BScrollView("scroll_trans", fTranslatorListView,
208     		B_FOLLOW_LEFT | B_FOLLOW_TOP_BOTTOM, B_WILL_DRAW | B_FRAME_EVENTS,
209     		false, true, B_FANCY_BORDER);
210 
211 	// Box around the config and info panels
212 	fRightBox = new BBox("Right_Side");
213 
214 	// Add the translator icon view
215 	fIconView = new IconView(BRect(0, 0, 31, 31), "Icon",
216 		B_FOLLOW_LEFT | B_FOLLOW_BOTTOM, B_WILL_DRAW | B_FRAME_EVENTS);
217 
218 	// Add the translator info button
219 	BButton *button = new BButton("STD", "Info" B_UTF8_ELLIPSIS,
220 		new BMessage(kMsgTranslatorInfo), B_WILL_DRAW | B_FRAME_EVENTS | B_NAVIGABLE);
221 
222 	// Add the translator name view
223 	fTranslatorNameView = new BStringView("TranName", "None");
224 
225 	// Populate the translators list view
226 	_PopulateListView();
227 
228 	// Build the layout
229 	BALMLayout *layout = new BALMLayout();
230 	mainView->SetLayout(layout);
231 
232 	XTab *x1 = layout->AddXTab();
233 	XTab *x2 = layout->AddXTab();
234 	XTab *x3 = layout->AddXTab();
235 	YTab *y1 = layout->AddYTab();
236 
237 	Area *leftArea = layout->AddArea(layout->Left(), layout->Top(),
238 		x1, layout->Bottom(), scrollView);
239 	leftArea->SetLeftInset(10);
240 	leftArea->SetTopInset(10);
241 	leftArea->SetBottomInset(10);
242 
243 	Area *rightArea = layout->AddArea(x1, layout->Top(), layout->Right(), y1, fRightBox);
244 	rightArea->SetLeftInset(10);
245 	rightArea->SetTopInset(10);
246 	rightArea->SetRightInset(10);
247 	rightArea->SetBottomInset(10);
248 
249 	Area *iconArea = layout->AddArea(x1, y1, x2, layout->Bottom(), fIconView);
250 	iconArea->SetLeftInset(10);
251 	iconArea->SetBottomInset(10);
252 
253 	Area *infoButtonArea = layout->AddArea(x3, y1, layout->Right(), layout->Bottom(), button);
254 	infoButtonArea->SetRightInset(10);
255 	infoButtonArea->SetBottomInset(10);
256 
257 	layout->AddConstraint(3.0, x1, -1.0, layout->Right(), OperatorType(EQ), 0.0);
258 
259 	fTranslatorListView->MakeFocus();
260 	fTranslatorListView->Select(0);
261 }
262 
263 
264 bool
265 DataTranslationsWindow::QuitRequested()
266 {
267 	BPoint pt(Frame().left, Frame().top);
268 	dynamic_cast<DataTranslationsApplication *>(be_app)->SetWindowCorner(pt);
269 	be_app->PostMessage(B_QUIT_REQUESTED);
270 
271 	return true;
272 }
273 
274 
275 void
276 DataTranslationsWindow::_ShowInfoAlert(int32 id)
277 {
278 	const char* name = NULL;
279 	const char* info = NULL;
280 	BPath path;
281 	int32 version = 0;
282 	_GetTranslatorInfo(id, name, info, version, path);
283 
284 	BString message;
285 	message << "Name: " << name << "\nVersion: ";
286 
287 	// Convert the version number into a readable format
288 	message << (int)B_TRANSLATION_MAJOR_VERSION(version)
289 		<< '.' << (int)B_TRANSLATION_MINOR_VERSION(version)
290 		<< '.' << (int)B_TRANSLATION_REVISION_VERSION(version);
291 	message << "\nInfo: " << info <<
292 		"\n\nPath:\n" << path.Path() << "\n";
293 
294 	BAlert *alert = new BAlert("info", message.String(), "OK");
295 	BTextView *view = alert->TextView();
296 	BFont font;
297 
298 	view->SetStylable(true);
299 
300 	view->GetFont(&font);
301 	font.SetFace(B_BOLD_FACE);
302 
303 	const char* labels[] = {"Name:", "Version:", "Info:", "Path:", NULL};
304 	for (int32 i = 0; labels[i]; i++) {
305 		int32 index = message.FindFirst(labels[i]);
306 		view->SetFontAndColor(index, index + strlen(labels[i]), &font);
307 	}
308 
309 	alert->Go();
310 }
311 
312 
313 void
314 DataTranslationsWindow::MessageReceived(BMessage *message)
315 {
316 	switch (message->what) {
317 		case kMsgTranslatorInfo:
318 		{
319 			int32 selected = fTranslatorListView->CurrentSelection(0);
320 			if (selected < 0) {
321 				// If no translator is selected, show a message explaining
322 				// what the config panel is for
323 				(new BAlert("Panel Info",
324 					"Translation Settings\n\n"
325 					"Use this control panel to set values that various\n"
326 					"translators use when no other settings are specified\n"
327 					"in the application.",
328 					"OK"))->Go();
329 				break;
330 			}
331 
332 			TranslatorItem* item = dynamic_cast<TranslatorItem*>(fTranslatorListView->ItemAt(selected));
333 			if (item != NULL)
334 				_ShowInfoAlert(item->ID());
335 			break;
336 		}
337 
338 		case kMsgSelectedTranslator:
339 		{
340 			// Update the icon and translator info panel
341 			// to match the new selection
342 
343 			int32 selected = fTranslatorListView->CurrentSelection(0);
344 			if (selected < 0) {
345 				// If none selected, clear the old one
346 				fIconView->DrawIcon(false);
347 				fTranslatorNameView->SetText("");
348 				fRightBox->RemoveChild(fConfigView);
349 				break;
350 			}
351 
352 			TranslatorItem* item = dynamic_cast<TranslatorItem*>(fTranslatorListView->ItemAt(selected));
353 			if (item == NULL)
354 				break;
355 
356 			_ShowConfigView(item->ID());
357 
358 			const char* name = NULL;
359 			const char* info = NULL;
360 			int32 version = 0;
361 			BPath path;
362 			_GetTranslatorInfo(item->ID(), name, info, version, path);
363 			fTranslatorNameView->SetText(path.Leaf());
364 			fIconView->SetIcon(path);
365 			break;
366 		}
367 
368 		case B_TRANSLATOR_ADDED:
369 		{
370 			int32 index = 0, id;
371 			while (message->FindInt32("translator_id", index++, &id) == B_OK) {
372 				const char* name;
373 				const char* info;
374 				int32 version;
375 				BPath path;
376 				if (_GetTranslatorInfo(id, name, info, version, path) == B_OK)
377 					fTranslatorListView->AddItem(new TranslatorItem(id, name));
378 			}
379 
380 			fTranslatorListView->SortItems();
381 			break;
382 		}
383 
384 		case B_TRANSLATOR_REMOVED:
385 		{
386 			int32 index = 0, id;
387 			while (message->FindInt32("translator_id", index++, &id) == B_OK) {
388 				for (int32 i = 0; i < fTranslatorListView->CountItems(); i++) {
389 					TranslatorItem* item = dynamic_cast<TranslatorItem*>(fTranslatorListView->ItemAt(i));
390 					if (item == NULL)
391 						continue;
392 
393 					if (item->ID() == (translator_id)id) {
394 						fTranslatorListView->RemoveItem(i);
395 						delete item;
396 						break;
397 					}
398 				}
399 			}
400 			break;
401 		}
402 
403 		default:
404 			BWindow::MessageReceived(message);
405 			break;
406 	}
407 }
408 
409