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