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