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