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