xref: /haiku/src/preferences/datatranslations/DataTranslationsWindow.cpp (revision d3d8b26997fac34a84981e6d2b649521de2cc45a)
1 /*
2  * Copyright 2002-2006, 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  */
10 
11 
12 #include "DataTranslations.h"
13 #include "DataTranslationsWindow.h"
14 #include "IconView.h"
15 #include "TranslatorListView.h"
16 
17 #include <Application.h>
18 #include <Screen.h>
19 #include <Alert.h>
20 #include <Bitmap.h>
21 #include <Box.h>
22 #include <Button.h>
23 #include <ListView.h>
24 #include <Path.h>
25 #include <ScrollView.h>
26 #include <String.h>
27 #include <StringView.h>
28 #include <TextView.h>
29 #include <TranslationDefs.h>
30 #include <TranslatorRoster.h>
31 
32 #define DTW_RIGHT	400
33 #define DTW_BOTTOM	300
34 
35 
36 const uint32 kMsgTranslatorInfo = 'trin';
37 const uint32 kMsgSelectedTranslator = 'trsl';
38 
39 
40 DataTranslationsWindow::DataTranslationsWindow()
41 	: BWindow(BRect(0, 0, DTW_RIGHT, DTW_BOTTOM),
42 		"DataTranslations", B_TITLED_WINDOW, B_NOT_ZOOMABLE | B_NOT_RESIZABLE)
43 {
44 	MoveTo(dynamic_cast<DataTranslationsApplication *>(be_app)->WindowCorner());
45 
46 	// Make sure that the window isn't positioned off screen
47 	BScreen screen;
48 	BRect scrf = screen.Frame(), winf = Frame();
49 	float x = winf.left, y = winf.top;
50 	scrf.top += 24;
51 	scrf.left += 5;
52 	scrf.right -= 5;
53 	if (winf.left < scrf.left)
54 		x = scrf.left;
55 	if (winf.right > scrf.right)
56 		x = scrf.right - winf.Width() - 5;
57 	if (winf.top < scrf.top)
58 		y = scrf.top;
59 	if (winf.bottom > scrf.bottom)
60 		y = scrf.bottom - winf.Height() - 15;
61 
62 	if (x != winf.left || y != winf.top)
63 		MoveTo(x, y);
64 
65 	_SetupViews();
66 
67 	BTranslatorRoster *roster = BTranslatorRoster::Default();
68 	roster->StartWatching(this);
69 
70 	Show();
71 }
72 
73 
74 DataTranslationsWindow::~DataTranslationsWindow()
75 {
76 	BTranslatorRoster *roster = BTranslatorRoster::Default();
77 	roster->StopWatching(this);
78 }
79 
80 
81 // Reads the installed translators and adds them to our BListView
82 status_t
83 DataTranslationsWindow::_PopulateListView()
84 {
85 	BTranslatorRoster *roster = BTranslatorRoster::Default();
86 
87 	// Get all Translators on the system. Gives us the number of translators
88 	// installed in num_translators and a reference to the first one
89 	int32 numTranslators;
90 	translator_id *translators = NULL;
91 	roster->GetAllTranslators(&translators, &numTranslators);
92 
93 	for (int32 i = 0; i < numTranslators; i++) {
94 		// Getting the first three Infos: Name, Info & Version
95 		int32 version;
96 		const char *name, *info;
97 		roster->GetTranslatorInfo(translators[i], &name, &info, &version);
98 		fTranslatorListView->AddItem(new TranslatorItem(translators[i], name));
99 	}
100 
101 	delete[] translators;
102 	return B_OK;
103 }
104 
105 
106 status_t
107 DataTranslationsWindow::_GetTranslatorInfo(int32 id, const char*& name,
108 	const char*& info, int32& version, BPath& path)
109 {
110 	// Returns information about the translator with the given id
111 
112 	if (id < 0)
113 		return B_BAD_VALUE;
114 
115 	BTranslatorRoster *roster = BTranslatorRoster::Default();
116 	if (roster->GetTranslatorInfo(id, &name, &info, &version) != B_OK)
117 		return B_ERROR;
118 
119 	// Get the translator's path
120 	entry_ref ref;
121 	if (roster->GetRefFor(id, &ref) == B_OK) {
122 		BEntry entry(&ref);
123 		path.SetTo(&entry);
124 	} else
125 		path.Unset();
126 
127 	return B_OK;
128 }
129 
130 
131 status_t
132 DataTranslationsWindow::_ShowConfigView(int32 id)
133 {
134 	// Shows the config panel for the translator with the given id
135 
136 	if (id < 0)
137 		return B_BAD_VALUE;
138 
139 	BTranslatorRoster *roster = BTranslatorRoster::Default();
140 
141 	// fConfigView is NULL the first time this function
142 	// is called, prevent a segment fault
143 	if (fConfigView)
144 		fRightBox->RemoveChild(fConfigView);
145 
146 	BMessage emptyMsg;
147 	BRect rect(0, 0, 200, 233);
148 	status_t ret = roster->MakeConfigurationView(id, &emptyMsg, &fConfigView, &rect);
149 	if (ret != B_OK) {
150 		fRightBox->RemoveChild(fConfigView);
151 		return ret;
152 	}
153 
154 	BRect configRect(fRightBox->Bounds());
155 	configRect.InsetBy(3, 3);
156 	configRect.bottom -= 45;
157 	float width = 0, height = 0;
158 	fConfigView->GetPreferredSize(&width, &height);
159 	float widen = max_c(0, width - configRect.Width());
160 	float heighten = max_c(0, height - configRect.Height());
161 	if (widen > 0 || heighten > 0) {
162 		ResizeBy(widen, heighten);
163 		configRect.right += widen;
164 		configRect.bottom += heighten;
165 	}
166 	fConfigView->MoveTo(configRect.left, configRect.top);
167 	fConfigView->ResizeTo(configRect.Width(), configRect.Height());
168 	fConfigView->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
169 		// force config views to all have the same color
170 	fRightBox->AddChild(fConfigView);
171 
172 	return B_OK;
173 }
174 
175 
176 void
177 DataTranslationsWindow::_SetupViews()
178 {
179 	fConfigView = NULL;
180 	// This is NULL until a translator is
181 	// selected from the listview
182 
183 	// Window box
184 	BView* mainView = new BView(Bounds(), "", B_FOLLOW_ALL, B_WILL_DRAW | B_FRAME_EVENTS);
185 	mainView->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
186 	AddChild(mainView);
187 
188 	// Add the translators list view
189 	fTranslatorListView = new TranslatorListView(BRect(10, 10, 120, Bounds().Height() - 10),
190 		"TransList", B_SINGLE_SELECTION_LIST);
191 	fTranslatorListView->SetSelectionMessage(new BMessage(kMsgSelectedTranslator));
192 
193 	BScrollView *scrollView = new BScrollView("scroll_trans", fTranslatorListView,
194     		B_FOLLOW_LEFT | B_FOLLOW_TOP_BOTTOM, B_WILL_DRAW | B_FRAME_EVENTS,
195     		false, true, B_FANCY_BORDER);
196 	mainView->AddChild(scrollView);
197 
198 	// Box around the config and info panels
199 	fRightBox = new BBox(BRect(130.0f + B_V_SCROLL_BAR_WIDTH, 8.0f, Bounds().Width() - 8.0f,
200 		Bounds().Height() - 8.0f), "Right_Side", B_FOLLOW_ALL);
201 	mainView->AddChild(fRightBox);
202 
203 	// Add the translator icon view
204 	BRect rightRect(fRightBox->Bounds()), iconRect(0, 0, 31, 31);
205 	rightRect.InsetBy(8, 8);
206 	iconRect.OffsetTo(rightRect.left, rightRect.bottom - iconRect.Height());
207 	fIconView = new IconView(iconRect, "Icon",
208 		B_FOLLOW_LEFT | B_FOLLOW_BOTTOM, B_WILL_DRAW | B_FRAME_EVENTS);
209 	fRightBox->AddChild(fIconView);
210 
211 	// Add the translator info button
212 	BRect infoRect(0, 0, 80, 20);
213 	BButton *button = new BButton(infoRect, "STD", "Info...",
214 		new BMessage(kMsgTranslatorInfo), B_FOLLOW_BOTTOM | B_FOLLOW_RIGHT,
215 		B_WILL_DRAW | B_FRAME_EVENTS | B_NAVIGABLE);
216 	button->ResizeToPreferred();
217 	button->MoveTo(fRightBox->Bounds().Width() - button->Bounds().Width() - 10.0f,
218 		fRightBox->Bounds().Height() - button->Bounds().Height() - 10.0f);
219 	fRightBox->AddChild(button);
220 
221 	// Add the translator name view
222 	BRect tranNameRect(iconRect.right + 5, iconRect.top,
223 		infoRect.left - 5, iconRect.bottom);
224 	fTranslatorNameView = new BStringView(tranNameRect, "TranName", "None",
225     		B_FOLLOW_LEFT | B_FOLLOW_BOTTOM);
226 	fRightBox->AddChild(fTranslatorNameView);
227 
228 	// Populate the translators list view
229 	_PopulateListView();
230 
231 	fTranslatorListView->MakeFocus();
232 	fTranslatorListView->Select(0, false);
233 }
234 
235 
236 bool
237 DataTranslationsWindow::QuitRequested()
238 {
239 	BPoint pt(Frame().left, Frame().top);
240 	dynamic_cast<DataTranslationsApplication *>(be_app)->SetWindowCorner(pt);
241 	be_app->PostMessage(B_QUIT_REQUESTED);
242 
243 	return true;
244 }
245 
246 
247 void
248 DataTranslationsWindow::_ShowInfoAlert(int32 id)
249 {
250 	const char* name = NULL;
251 	const char* info = NULL;
252 	BPath path;
253 	int32 version = 0;
254 	_GetTranslatorInfo(id, name, info, version, path);
255 
256 	BString message;
257 	message << "Name: " << name << "\nVersion: ";
258 
259 	// Convert the version number into a readable format
260 	message << (int)B_TRANSLATION_MAJOR_VERSION(version)
261 		<< '.' << (int)B_TRANSLATION_MINOR_VERSION(version)
262 		<< '.' << (int)B_TRANSLATION_REVISION_VERSION(version);
263 	message << "\nInfo: " << info <<
264 		"\n\nPath:\n" << path.Path() << "\n";
265 
266 	BAlert *alert = new BAlert("info", message.String(), "OK");
267 	BTextView *view = alert->TextView();
268 	BFont font;
269 
270 	view->SetStylable(true);
271 
272 	view->GetFont(&font);
273 	font.SetFace(B_BOLD_FACE);
274 
275 	const char* labels[] = {"Name:", "Version:", "Info:", "Path:", NULL};
276 	for (int32 i = 0; labels[i]; i++) {
277 		int32 index = message.FindFirst(labels[i]);
278 		view->SetFontAndColor(index, index + strlen(labels[i]), &font);
279 	}
280 
281 	alert->Go();
282 }
283 
284 
285 void
286 DataTranslationsWindow::MessageReceived(BMessage *message)
287 {
288 	switch (message->what) {
289 		case kMsgTranslatorInfo:
290 		{
291 			int32 selected = fTranslatorListView->CurrentSelection(0);
292 			if (selected < 0) {
293 				// If no translator is selected, show a message explaining
294 				// what the config panel is for
295 				(new BAlert("Panel Info",
296 					"Translation Settings\n\n"
297 					"Use this control panel to set values that various\n"
298 					"translators use when no other settings are specified\n"
299 					"in the application.",
300 					"OK"))->Go();
301 				break;
302 			}
303 
304 			TranslatorItem* item = dynamic_cast<TranslatorItem*>(fTranslatorListView->ItemAt(selected));
305 			if (item != NULL)
306 				_ShowInfoAlert(item->ID());
307 			break;
308 		}
309 
310 		case kMsgSelectedTranslator:
311 		{
312 			// Update the icon and translator info panel
313 			// to match the new selection
314 
315 			int32 selected = fTranslatorListView->CurrentSelection(0);
316 			if (selected < 0) {
317 				// If none selected, clear the old one
318 				fIconView->DrawIcon(false);
319 				fTranslatorNameView->SetText("");
320 				fRightBox->RemoveChild(fConfigView);
321 				break;
322 			}
323 
324 			TranslatorItem* item = dynamic_cast<TranslatorItem*>(fTranslatorListView->ItemAt(selected));
325 			if (item == NULL)
326 				break;
327 
328 			_ShowConfigView(item->ID());
329 
330 			const char* name = NULL;
331 			const char* info = NULL;
332 			int32 version = 0;
333 			BPath path;
334 			_GetTranslatorInfo(item->ID(), name, info, version, path);
335 			fTranslatorNameView->SetText(path.Leaf());
336 			fIconView->SetIcon(path);
337 			break;
338 		}
339 
340 		case B_TRANSLATOR_ADDED:
341 		{
342 			int32 index = 0, id;
343 			while (message->FindInt32("translator_id", index++, &id) == B_OK) {
344 				const char* name;
345 				const char* info;
346 				int32 version;
347 				BPath path;
348 				if (_GetTranslatorInfo(id, name, info, version, path) == B_OK)
349 					fTranslatorListView->AddItem(new TranslatorItem(id, name));
350 			}
351 
352 			fTranslatorListView->SortItems();
353 			break;
354 		}
355 
356 		case B_TRANSLATOR_REMOVED:
357 		{
358 			int32 index = 0, id;
359 			while (message->FindInt32("translator_id", index++, &id) == B_OK) {
360 				for (int32 i = 0; i < fTranslatorListView->CountItems(); i++) {
361 					TranslatorItem* item = dynamic_cast<TranslatorItem*>(fTranslatorListView->ItemAt(i));
362 					if (item == NULL)
363 						continue;
364 
365 					if (item->ID() == (translator_id)id) {
366 						fTranslatorListView->RemoveItem(i);
367 						delete item;
368 						break;
369 					}
370 				}
371 			}
372 			break;
373 		}
374 
375 		default:
376 			BWindow::MessageReceived(message);
377 			break;
378 	}
379 }
380 
381