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