1 /* 2 * Copyright 2002-2009, 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 "DataTranslations.h" 14 #include "DataTranslationsWindow.h" 15 #include "IconView.h" 16 #include "TranslatorListView.h" 17 18 #include <Application.h> 19 #include <Screen.h> 20 #include <Alert.h> 21 #include <Bitmap.h> 22 #include <Box.h> 23 #include <Button.h> 24 #include <ListView.h> 25 #include <Path.h> 26 #include <ScrollView.h> 27 #include <String.h> 28 #include <StringView.h> 29 #include <TextView.h> 30 #include <TranslationDefs.h> 31 #include <TranslatorRoster.h> 32 33 #include "Area.h" 34 #include "BALMLayout.h" 35 #include "OperatorType.h" 36 #include "XTab.h" 37 #include "YTab.h" 38 39 #define DTW_RIGHT 400 40 #define DTW_BOTTOM 300 41 42 43 const uint32 kMsgTranslatorInfo = 'trin'; 44 const uint32 kMsgSelectedTranslator = 'trsl'; 45 46 47 DataTranslationsWindow::DataTranslationsWindow() 48 : BWindow(BRect(0, 0, DTW_RIGHT, DTW_BOTTOM), 49 "DataTranslations", B_TITLED_WINDOW, 50 B_ASYNCHRONOUS_CONTROLS | B_NOT_ZOOMABLE | B_NOT_RESIZABLE | B_AUTO_UPDATE_SIZE_LIMITS) 51 { 52 MoveTo(dynamic_cast<DataTranslationsApplication *>(be_app)->WindowCorner()); 53 54 // Make sure that the window isn't positioned off screen 55 BScreen screen; 56 BRect scrf = screen.Frame(), winf = Frame(); 57 float x = winf.left, y = winf.top; 58 scrf.top += 24; 59 scrf.left += 5; 60 scrf.right -= 5; 61 if (winf.left < scrf.left) 62 x = scrf.left; 63 if (winf.right > scrf.right) 64 x = scrf.right - winf.Width() - 5; 65 if (winf.top < scrf.top) 66 y = scrf.top; 67 if (winf.bottom > scrf.bottom) 68 y = scrf.bottom - winf.Height() - 15; 69 70 if (x != winf.left || y != winf.top) 71 MoveTo(x, y); 72 73 _SetupViews(); 74 75 BTranslatorRoster *roster = BTranslatorRoster::Default(); 76 roster->StartWatching(this); 77 78 Show(); 79 } 80 81 82 DataTranslationsWindow::~DataTranslationsWindow() 83 { 84 BTranslatorRoster *roster = BTranslatorRoster::Default(); 85 roster->StopWatching(this); 86 } 87 88 89 // Reads the installed translators and adds them to our BListView 90 status_t 91 DataTranslationsWindow::_PopulateListView() 92 { 93 BTranslatorRoster *roster = BTranslatorRoster::Default(); 94 95 // Get all Translators on the system. Gives us the number of translators 96 // installed in num_translators and a reference to the first one 97 int32 numTranslators; 98 translator_id *translators = NULL; 99 roster->GetAllTranslators(&translators, &numTranslators); 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, *info; 105 roster->GetTranslatorInfo(translators[i], &name, &info, &version); 106 fTranslatorListView->AddItem(new TranslatorItem(translators[i], name)); 107 } 108 109 delete[] translators; 110 return B_OK; 111 } 112 113 114 status_t 115 DataTranslationsWindow::_GetTranslatorInfo(int32 id, const char*& name, 116 const char*& info, int32& version, BPath& path) 117 { 118 // Returns information about the translator with the given id 119 120 if (id < 0) 121 return B_BAD_VALUE; 122 123 BTranslatorRoster *roster = BTranslatorRoster::Default(); 124 if (roster->GetTranslatorInfo(id, &name, &info, &version) != B_OK) 125 return B_ERROR; 126 127 // Get the translator's path 128 entry_ref ref; 129 if (roster->GetRefFor(id, &ref) == B_OK) { 130 BEntry entry(&ref); 131 path.SetTo(&entry); 132 } else 133 path.Unset(); 134 135 return B_OK; 136 } 137 138 139 status_t 140 DataTranslationsWindow::_ShowConfigView(int32 id) 141 { 142 // Shows the config panel for the translator with the given id 143 144 if (id < 0) 145 return B_BAD_VALUE; 146 147 BTranslatorRoster *roster = BTranslatorRoster::Default(); 148 149 // fConfigView is NULL the first time this function 150 // is called, prevent a segment fault 151 if (fConfigView) 152 fRightBox->RemoveChild(fConfigView); 153 154 BMessage emptyMsg; 155 BRect rect(0, 0, 200, 233); 156 status_t ret = roster->MakeConfigurationView(id, &emptyMsg, &fConfigView, &rect); 157 if (ret != B_OK) { 158 fRightBox->RemoveChild(fConfigView); 159 return ret; 160 } 161 162 BRect configRect(fRightBox->Bounds()); 163 configRect.InsetBy(3, 3); 164 configRect.bottom -= 45; 165 float width = 0, height = 0; 166 if ((fConfigView->Flags() & B_SUPPORTS_LAYOUT) != 0) { 167 BSize configSize = fConfigView->ExplicitPreferredSize(); 168 width = configSize.Width(); 169 height = configSize.Height(); 170 } else { 171 fConfigView->GetPreferredSize(&width, &height); 172 } 173 float widen = max_c(0, width - configRect.Width()); 174 float heighten = max_c(0, height - configRect.Height()); 175 if (widen > 0 || heighten > 0) { 176 ResizeBy(widen, heighten); 177 configRect.right += widen; 178 configRect.bottom += heighten; 179 } 180 fConfigView->MoveTo(configRect.left, configRect.top); 181 fConfigView->ResizeTo(configRect.Width(), configRect.Height()); 182 fConfigView->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); 183 // force config views to all have the same color 184 fRightBox->AddChild(fConfigView); 185 186 return B_OK; 187 } 188 189 190 void 191 DataTranslationsWindow::_SetupViews() 192 { 193 fConfigView = NULL; 194 // This is NULL until a translator is 195 // selected from the listview 196 197 // Window box 198 BView* mainView = new BView(Bounds(), "", B_FOLLOW_ALL, B_WILL_DRAW | B_FRAME_EVENTS); 199 mainView->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); 200 AddChild(mainView); 201 202 // Add the translators list view 203 fTranslatorListView = new TranslatorListView(BRect(0, 0, 1, 1), "TransList", 204 B_SINGLE_SELECTION_LIST); 205 fTranslatorListView->SetSelectionMessage(new BMessage(kMsgSelectedTranslator)); 206 207 BScrollView *scrollView = new BScrollView("scroll_trans", fTranslatorListView, 208 B_FOLLOW_LEFT | B_FOLLOW_TOP_BOTTOM, B_WILL_DRAW | B_FRAME_EVENTS, 209 false, true, B_FANCY_BORDER); 210 211 // Box around the config and info panels 212 fRightBox = new BBox("Right_Side"); 213 214 // Add the translator icon view 215 fIconView = new IconView(BRect(0, 0, 31, 31), "Icon", 216 B_FOLLOW_LEFT | B_FOLLOW_BOTTOM, B_WILL_DRAW | B_FRAME_EVENTS); 217 218 // Add the translator info button 219 BButton *button = new BButton("STD", "Info" B_UTF8_ELLIPSIS, 220 new BMessage(kMsgTranslatorInfo), B_WILL_DRAW | B_FRAME_EVENTS | B_NAVIGABLE); 221 222 // Add the translator name view 223 fTranslatorNameView = new BStringView("TranName", "None"); 224 225 // Populate the translators list view 226 _PopulateListView(); 227 228 // Build the layout 229 BALMLayout *layout = new BALMLayout(); 230 mainView->SetLayout(layout); 231 232 XTab *x1 = layout->AddXTab(); 233 XTab *x2 = layout->AddXTab(); 234 XTab *x3 = layout->AddXTab(); 235 YTab *y1 = layout->AddYTab(); 236 237 Area *leftArea = layout->AddArea(layout->Left(), layout->Top(), 238 x1, layout->Bottom(), scrollView); 239 leftArea->SetLeftInset(10); 240 leftArea->SetTopInset(10); 241 leftArea->SetBottomInset(10); 242 243 Area *rightArea = layout->AddArea(x1, layout->Top(), layout->Right(), y1, fRightBox); 244 rightArea->SetLeftInset(10); 245 rightArea->SetTopInset(10); 246 rightArea->SetRightInset(10); 247 rightArea->SetBottomInset(10); 248 249 Area *iconArea = layout->AddArea(x1, y1, x2, layout->Bottom(), fIconView); 250 iconArea->SetLeftInset(10); 251 iconArea->SetBottomInset(10); 252 253 Area *infoButtonArea = layout->AddArea(x3, y1, layout->Right(), layout->Bottom(), button); 254 infoButtonArea->SetRightInset(10); 255 infoButtonArea->SetBottomInset(10); 256 257 layout->AddConstraint(3.0, x1, -1.0, layout->Right(), OperatorType(EQ), 0.0); 258 259 fTranslatorListView->MakeFocus(); 260 fTranslatorListView->Select(0); 261 } 262 263 264 bool 265 DataTranslationsWindow::QuitRequested() 266 { 267 BPoint pt(Frame().left, Frame().top); 268 dynamic_cast<DataTranslationsApplication *>(be_app)->SetWindowCorner(pt); 269 be_app->PostMessage(B_QUIT_REQUESTED); 270 271 return true; 272 } 273 274 275 void 276 DataTranslationsWindow::_ShowInfoAlert(int32 id) 277 { 278 const char* name = NULL; 279 const char* info = NULL; 280 BPath path; 281 int32 version = 0; 282 _GetTranslatorInfo(id, name, info, version, path); 283 284 BString message; 285 message << "Name: " << name << "\nVersion: "; 286 287 // Convert the version number into a readable format 288 message << (int)B_TRANSLATION_MAJOR_VERSION(version) 289 << '.' << (int)B_TRANSLATION_MINOR_VERSION(version) 290 << '.' << (int)B_TRANSLATION_REVISION_VERSION(version); 291 message << "\nInfo: " << info << 292 "\n\nPath:\n" << path.Path() << "\n"; 293 294 BAlert *alert = new BAlert("info", message.String(), "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[] = {"Name:", "Version:", "Info:", "Path:", NULL}; 304 for (int32 i = 0; labels[i]; i++) { 305 int32 index = message.FindFirst(labels[i]); 306 view->SetFontAndColor(index, index + strlen(labels[i]), &font); 307 } 308 309 alert->Go(); 310 } 311 312 313 void 314 DataTranslationsWindow::MessageReceived(BMessage *message) 315 { 316 switch (message->what) { 317 case kMsgTranslatorInfo: 318 { 319 int32 selected = fTranslatorListView->CurrentSelection(0); 320 if (selected < 0) { 321 // If no translator is selected, show a message explaining 322 // what the config panel is for 323 (new BAlert("Panel Info", 324 "Translation Settings\n\n" 325 "Use this control panel to set values that various\n" 326 "translators use when no other settings are specified\n" 327 "in the application.", 328 "OK"))->Go(); 329 break; 330 } 331 332 TranslatorItem* item = dynamic_cast<TranslatorItem*>(fTranslatorListView->ItemAt(selected)); 333 if (item != NULL) 334 _ShowInfoAlert(item->ID()); 335 break; 336 } 337 338 case kMsgSelectedTranslator: 339 { 340 // Update the icon and translator info panel 341 // to match the new selection 342 343 int32 selected = fTranslatorListView->CurrentSelection(0); 344 if (selected < 0) { 345 // If none selected, clear the old one 346 fIconView->DrawIcon(false); 347 fTranslatorNameView->SetText(""); 348 fRightBox->RemoveChild(fConfigView); 349 break; 350 } 351 352 TranslatorItem* item = dynamic_cast<TranslatorItem*>(fTranslatorListView->ItemAt(selected)); 353 if (item == NULL) 354 break; 355 356 _ShowConfigView(item->ID()); 357 358 const char* name = NULL; 359 const char* info = NULL; 360 int32 version = 0; 361 BPath path; 362 _GetTranslatorInfo(item->ID(), name, info, version, path); 363 fTranslatorNameView->SetText(path.Leaf()); 364 fIconView->SetIcon(path); 365 break; 366 } 367 368 case B_TRANSLATOR_ADDED: 369 { 370 int32 index = 0, id; 371 while (message->FindInt32("translator_id", index++, &id) == B_OK) { 372 const char* name; 373 const char* info; 374 int32 version; 375 BPath path; 376 if (_GetTranslatorInfo(id, name, info, version, path) == B_OK) 377 fTranslatorListView->AddItem(new TranslatorItem(id, name)); 378 } 379 380 fTranslatorListView->SortItems(); 381 break; 382 } 383 384 case B_TRANSLATOR_REMOVED: 385 { 386 int32 index = 0, id; 387 while (message->FindInt32("translator_id", index++, &id) == B_OK) { 388 for (int32 i = 0; i < fTranslatorListView->CountItems(); i++) { 389 TranslatorItem* item = dynamic_cast<TranslatorItem*>(fTranslatorListView->ItemAt(i)); 390 if (item == NULL) 391 continue; 392 393 if (item->ID() == (translator_id)id) { 394 fTranslatorListView->RemoveItem(i); 395 delete item; 396 break; 397 } 398 } 399 } 400 break; 401 } 402 403 default: 404 BWindow::MessageReceived(message); 405 break; 406 } 407 } 408 409