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