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