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