xref: /haiku/src/preferences/datatranslations/DataTranslationsWindow.cpp (revision 8341933096ea21251fd26a216168f8b0beff7781)
1 /*
2  * Copyright 2002-2017, 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 "DataTranslationsWindow.h"
14 
15 #include <algorithm>
16 
17 #include <math.h>
18 #include <stdio.h>
19 
20 #include <Alert.h>
21 #include <Alignment.h>
22 #include <Application.h>
23 #include <Bitmap.h>
24 #include <Box.h>
25 #include <Catalog.h>
26 #include <ControlLook.h>
27 #include <Entry.h>
28 #include <GroupView.h>
29 #include <IconView.h>
30 #include <LayoutBuilder.h>
31 #include <ListView.h>
32 #include <Path.h>
33 #include <Screen.h>
34 #include <ScrollView.h>
35 #include <String.h>
36 #include <StringView.h>
37 #include <SupportDefs.h>
38 #include <TextView.h>
39 #include <TranslationDefs.h>
40 #include <TranslatorRoster.h>
41 
42 
43 #include "DataTranslations.h"
44 #include "DataTranslationsSettings.h"
45 #include "TranslatorListView.h"
46 
47 
48 #undef B_TRANSLATION_CONTEXT
49 #define B_TRANSLATION_CONTEXT "DataTranslations"
50 
51 
52 const uint32 kMsgTranslatorInfo = 'trin';
53 const uint32 kMsgSelectedTranslator = 'trsl';
54 
55 
DataTranslationsWindow()56 DataTranslationsWindow::DataTranslationsWindow()
57 	:
58 	BWindow(BRect(0.0f, 0.0f, 597.0f, 368.0f),
59 		B_TRANSLATE_SYSTEM_NAME("DataTranslations"),
60 		B_TITLED_WINDOW, B_ASYNCHRONOUS_CONTROLS | B_NOT_RESIZABLE
61 			| B_NOT_ZOOMABLE | B_AUTO_UPDATE_SIZE_LIMITS),
62 	fRelease(NULL)
63 {
64 	MoveTo(DataTranslationsSettings::Instance()->WindowCorner());
65 
66 	_SetupViews();
67 
68 	// Make sure that the window isn't positioned off screen
69 	BScreen screen;
70 	BRect screenFrame = screen.Frame();
71 	if (!screenFrame.Contains(Frame()))
72 		CenterOnScreen();
73 
74 	BTranslatorRoster* roster = BTranslatorRoster::Default();
75 	roster->StartWatching(this);
76 
77 	Show();
78 }
79 
80 
~DataTranslationsWindow()81 DataTranslationsWindow::~DataTranslationsWindow()
82 {
83 	BTranslatorRoster* roster = BTranslatorRoster::Default();
84 	roster->StopWatching(this);
85 }
86 
87 
88 // Reads the installed translators and adds them to our BListView
89 status_t
_PopulateListView()90 DataTranslationsWindow::_PopulateListView()
91 {
92 	BTranslatorRoster* roster = BTranslatorRoster::Default();
93 
94 	// Get all Translators on the system. Gives us the number of translators
95 	// installed in num_translators and a reference to the first one
96 	int32 numTranslators;
97 	translator_id* translators = NULL;
98 	roster->GetAllTranslators(&translators, &numTranslators);
99 
100 	float maxWidth = 0;
101 
102 	for (int32 i = 0; i < numTranslators; i++) {
103 		// Getting the first three Infos: Name, Info & Version
104 		int32 version;
105 		const char* name;
106 		const char* info;
107 		roster->GetTranslatorInfo(translators[i], &name, &info, &version);
108 		fTranslatorListView->AddItem(new TranslatorItem(translators[i], name));
109 		maxWidth = std::max(maxWidth, fTranslatorListView->StringWidth(name));
110 	}
111 
112 	fTranslatorListView->SortItems();
113 
114 	fTranslatorListView->SetExplicitSize(BSize(maxWidth + 20, B_SIZE_UNSET));
115 
116 	delete[] translators;
117 	return B_OK;
118 }
119 
120 
121 status_t
_GetTranslatorInfo(int32 id,const char * & name,const char * & info,int32 & version,BPath & path)122 DataTranslationsWindow::_GetTranslatorInfo(int32 id, const char*& name,
123 	const char*& info, int32& version, BPath& path)
124 {
125 	// Returns information about the translator with the given id
126 
127 	if (id < 0)
128 		return B_BAD_VALUE;
129 
130 	BTranslatorRoster* roster = BTranslatorRoster::Default();
131 	if (roster->GetTranslatorInfo(id, &name, &info, &version) != B_OK)
132 		return B_ERROR;
133 
134 	// Get the translator's path
135 	entry_ref ref;
136 	if (roster->GetRefFor(id, &ref) == B_OK) {
137 		BEntry entry(&ref);
138 		path.SetTo(&entry);
139 	} else
140 		path.Unset();
141 
142 	return B_OK;
143 }
144 
145 
146 status_t
_ShowConfigView(int32 id)147 DataTranslationsWindow::_ShowConfigView(int32 id)
148 {
149 	// Shows the config panel for the translator with the given id
150 
151 	if (id < 0)
152 		return B_BAD_VALUE;
153 
154 	BTranslatorRoster* roster = BTranslatorRoster::Default();
155 
156 	if (fConfigView != NULL) {
157 		fRightBox->RemoveChild(fConfigView);
158 		delete fConfigView;
159 		fConfigView = NULL;
160 		fInfoText = NULL;
161 		if (fRelease != NULL) {
162 			fRelease->Release();
163 			fRelease = NULL;
164 		}
165 	}
166 
167 	BMessage emptyMessage;
168 	BRect rect(0.0f, 0.0f, 200.0f, 233.0f);
169 	status_t result = roster->MakeConfigurationView(id, &emptyMessage,
170 		&fConfigView, &rect);
171 
172 	if (result != B_OK)
173 		return result;
174 
175 	fConfigView->SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
176 		// force config views to all have the same color
177 	fRightBox->AddChild(fConfigView);
178 
179 	// for default 12pt font size: 597 ≈ (0.85 * 12 * 49)
180 	fConfigView->SetExplicitMinSize(
181 		BSize(ceilf(be_control_look->DefaultItemSpacing() * 49)
182 			- fTranslatorListView->Frame().Width(), B_SIZE_UNSET));
183 
184 	// Make sure the translator's image doesn't get unloaded while we are still
185 	// showing a config view whose code is in the image
186 	fRelease = roster->AcquireTranslator(id);
187 
188 	return B_OK;
189 }
190 
191 
192 void
_ShowInfoView()193 DataTranslationsWindow::_ShowInfoView()
194 {
195 	if (fConfigView != NULL) {
196 		fRightBox->RemoveChild(fConfigView);
197 		delete fConfigView;
198 		fConfigView = NULL;
199 		fInfoText = NULL;
200 		if (fRelease != NULL) {
201 			fRelease->Release();
202 			fRelease = NULL;
203 		}
204 	}
205 
206 	fInfoText = new BTextView("info text");
207 	fInfoText->MakeEditable(false);
208 	fInfoText->MakeSelectable(false);
209 	fInfoText->SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
210 	fInfoText->SetText(B_TRANSLATE(
211 		"Use this control panel to set default values for translators, "
212 		"to be used when no other settings are specified by an application."));
213 	rgb_color textColor = ui_color(B_PANEL_TEXT_COLOR);
214 	fInfoText->SetFontAndColor(be_plain_font, B_FONT_ALL, &textColor);
215 
216 	BGroupView* group = new BGroupView(B_VERTICAL);
217 	group->AddChild(fInfoText);
218 	float spacing = be_control_look->DefaultItemSpacing();
219 	group->GroupLayout()->SetInsets(spacing, spacing, spacing, spacing);
220 	fRightBox->AddChild(group);
221 	fConfigView = group;
222 
223 	fConfigView->SetExplicitMinSize(
224 		BSize(ceilf(spacing * be_plain_font->Size() * 0.7)
225 			- fTranslatorListView->Frame().Width(),
226 			ceilf(spacing * be_plain_font->Size() * 0.4)));
227 }
228 
229 
230 void
_SetupViews()231 DataTranslationsWindow::_SetupViews()
232 {
233 	fInfoText = NULL;
234 	fConfigView = NULL;
235 	// This is NULL until a translator is
236 	// selected from the listview
237 
238 	// Add the translators list view
239 	fTranslatorListView = new TranslatorListView("TransList");
240 	fTranslatorListView->SetSelectionMessage(
241 		new BMessage(kMsgSelectedTranslator));
242 
243 	BScrollView* scrollView = new BScrollView("scroll_trans",
244 		fTranslatorListView, B_WILL_DRAW | B_FRAME_EVENTS, false,
245 		true, B_FANCY_BORDER);
246 
247 	// Box around the config and info panels
248 	fRightBox = new BBox("Right_Side");
249 	fRightBox->SetExplicitAlignment(BAlignment(B_ALIGN_USE_FULL_WIDTH,
250 		B_ALIGN_USE_FULL_HEIGHT));
251 
252 	// Add the translator icon view
253 	fIconView = new IconView();
254 
255 	// Add the translator info button
256 	fButton = new BButton("info", B_TRANSLATE("Info"),
257 		new BMessage(kMsgTranslatorInfo),
258 		B_WILL_DRAW | B_FRAME_EVENTS | B_NAVIGABLE);
259 	fButton->SetEnabled(false);
260 
261 	// Populate the translators list view
262 	_PopulateListView();
263 
264 	// Build the layout
265 	BLayoutBuilder::Group<>(this, B_HORIZONTAL)
266 		.SetInsets(B_USE_WINDOW_SPACING)
267 		.Add(scrollView, 3)
268 		.AddGroup(B_VERTICAL)
269 			.Add(fRightBox)
270 			.AddGroup(B_HORIZONTAL)
271 				.Add(fIconView)
272 				.AddGlue()
273 				.Add(fButton)
274 				.End()
275 			.End()
276 		.End();
277 
278 	fTranslatorListView->MakeFocus();
279 	_ShowInfoView();
280 }
281 
282 
283 bool
QuitRequested()284 DataTranslationsWindow::QuitRequested()
285 {
286 	BPoint pt(Frame().LeftTop());
287 	DataTranslationsSettings::Instance()->SetWindowCorner(pt);
288 	be_app->PostMessage(B_QUIT_REQUESTED);
289 	return true;
290 }
291 
292 
293 void
_ShowInfoAlert(int32 id)294 DataTranslationsWindow::_ShowInfoAlert(int32 id)
295 {
296 	const char* name = NULL;
297 	const char* info = NULL;
298 	BPath path;
299 	int32 version = 0;
300 	_GetTranslatorInfo(id, name, info, version, path);
301 
302 	const char* labels[] = { B_TRANSLATE("Name:"), B_TRANSLATE("Version:"),
303 		B_TRANSLATE("Info:"), B_TRANSLATE("Path:"), NULL };
304 	int offsets[4];
305 
306 	BString message;
307 	BString temp;
308 
309 	offsets[0] = 0;
310 	temp.SetToFormat("%s %s\n", labels[0], name);
311 
312 	message.Append(temp);
313 
314 	offsets[1] = message.Length();
315 	// Convert the version number into a readable format
316 	temp.SetToFormat("%s %" B_PRId32 ".%" B_PRId32 ".%" B_PRId32 "\n\n", labels[1],
317 		B_TRANSLATION_MAJOR_VERSION(version),
318 		B_TRANSLATION_MINOR_VERSION(version),
319 		B_TRANSLATION_REVISION_VERSION(version));
320 
321 	message.Append(temp);
322 
323 	offsets[2] = message.Length();
324 	temp.SetToFormat("%s\n%s\n\n", labels[2], info);
325 
326 	message.Append(temp);
327 
328 	offsets[3] = message.Length();
329 	temp.SetToFormat("%s %s\n", labels[3], path.Path());
330 
331 	message.Append(temp);
332 
333 	BAlert* alert = new BAlert(B_TRANSLATE("Info"), message.String(),
334 		B_TRANSLATE("OK"));
335 	BTextView* view = alert->TextView();
336 	BFont font;
337 
338 	view->SetStylable(true);
339 
340 	view->GetFont(&font);
341 	font.SetFace(B_BOLD_FACE);
342 
343 	for (int32 i = 0; labels[i]; i++) {
344 		view->SetFontAndColor(offsets[i], offsets[i] + strlen(labels[i]), &font);
345 	}
346 
347 	alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
348 	alert->Go();
349 }
350 
351 
352 void
MessageReceived(BMessage * message)353 DataTranslationsWindow::MessageReceived(BMessage* message)
354 {
355 	switch (message->what) {
356 		case kMsgTranslatorInfo:
357 		{
358 			int32 selected = fTranslatorListView->CurrentSelection(0);
359 			if (selected < 0)
360 				break;
361 
362 			TranslatorItem* item = fTranslatorListView->TranslatorAt(selected);
363 			if (item != NULL)
364 				_ShowInfoAlert(item->ID());
365 			break;
366 		}
367 
368 		case kMsgSelectedTranslator:
369 		{
370 			// Update the icon and translator info panel
371 			// to match the new selection
372 
373 			int32 selected = fTranslatorListView->CurrentSelection(0);
374 			if (selected < 0) {
375 				// If none selected, clear the old one
376 				fIconView->DrawIcon(false);
377 				fButton->SetEnabled(false);
378 				fRightBox->RemoveChild(fConfigView);
379 				_ShowInfoView();
380 				break;
381 			}
382 
383 			TranslatorItem* item = fTranslatorListView->TranslatorAt(selected);
384 			if (item == NULL)
385 				break;
386 
387 			_ShowConfigView(item->ID());
388 
389 			const char* name = NULL;
390 			const char* info = NULL;
391 			int32 version = 0;
392 			BPath path;
393 			_GetTranslatorInfo(item->ID(), name, info, version, path);
394 			fIconView->SetIcon(path);
395 			fButton->SetEnabled(true);
396 			break;
397 		}
398 
399 		case B_COLORS_UPDATED:
400 		{
401 			if (fInfoText == NULL || fInfoText->Parent() == NULL)
402 				break;
403 
404 			rgb_color color;
405 			if (message->FindColor(ui_color_name(B_PANEL_TEXT_COLOR), &color)
406 					== B_OK) {
407 				fInfoText->SetFontAndColor(be_plain_font, B_FONT_ALL, &color);
408 			}
409 			break;
410 		}
411 
412 		case B_TRANSLATOR_ADDED:
413 		{
414 			int32 index = 0;
415 			int32 id;
416 			while (message->FindInt32("translator_id", index++, &id) == B_OK) {
417 				const char* name;
418 				const char* info;
419 				int32 version;
420 				BPath path;
421 				if (_GetTranslatorInfo(id, name, info, version, path) == B_OK)
422 					fTranslatorListView->AddItem(new TranslatorItem(id, name));
423 			}
424 
425 			fTranslatorListView->SortItems();
426 			break;
427 		}
428 
429 		case B_TRANSLATOR_REMOVED:
430 		{
431 			int32 index = 0;
432 			int32 id;
433 			while (message->FindInt32("translator_id", index++, &id) == B_OK) {
434 				for (int32 i = 0; i < fTranslatorListView->CountItems(); i++) {
435 					TranslatorItem* item = fTranslatorListView->TranslatorAt(i);
436 
437 					if (item == NULL)
438 						continue;
439 
440 					if (item->ID() == (translator_id)id) {
441 						fTranslatorListView->RemoveItem(i);
442 						delete item;
443 						break;
444 					}
445 				}
446 			}
447 			break;
448 		}
449 
450 		default:
451 			BWindow::MessageReceived(message);
452 			break;
453 	}
454 }
455