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