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