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