/*
* Copyright 2002-2017, Haiku, Inc.
* Distributed under the terms of the MIT license.
*
* Authors:
* Oliver Siebenmarck
* Andrew McCall, mccall@digitalparadise.co.uk
* Michael Wilber
* Maxime Simon
*/
#include "DataTranslationsWindow.h"
#include <algorithm>
#include <math.h>
#include <stdio.h>
#include <Alert.h>
#include <Alignment.h>
#include <Application.h>
#include <Bitmap.h>
#include <Box.h>
#include <Catalog.h>
#include <ControlLook.h>
#include <Entry.h>
#include <GroupView.h>
#include <IconView.h>
#include <LayoutBuilder.h>
#include <ListView.h>
#include <Path.h>
#include <Screen.h>
#include <ScrollView.h>
#include <String.h>
#include <StringView.h>
#include <SupportDefs.h>
#include <TextView.h>
#include <TranslationDefs.h>
#include <TranslatorRoster.h>
#include "DataTranslations.h"
#include "DataTranslationsSettings.h"
#include "TranslatorListView.h"
#undef B_TRANSLATION_CONTEXT
#define B_TRANSLATION_CONTEXT "DataTranslations"
const uint32 kMsgTranslatorInfo = 'trin';
const uint32 kMsgSelectedTranslator = 'trsl';
DataTranslationsWindow::DataTranslationsWindow()
:
BWindow(BRect(0.0f, 0.0f, 597.0f, 368.0f),
B_TRANSLATE_SYSTEM_NAME("DataTranslations"),
B_TITLED_WINDOW, B_ASYNCHRONOUS_CONTROLS | B_NOT_RESIZABLE
| B_NOT_ZOOMABLE | B_AUTO_UPDATE_SIZE_LIMITS),
fRelease(NULL)
{
MoveTo(DataTranslationsSettings::Instance()->WindowCorner());
_SetupViews();
// Make sure that the window isn't positioned off screen
BScreen screen;
BRect screenFrame = screen.Frame();
if (!screenFrame.Contains(Frame()))
CenterOnScreen();
BTranslatorRoster* roster = BTranslatorRoster::Default();
roster->StartWatching(this);
Show();
}
DataTranslationsWindow::~DataTranslationsWindow()
{
BTranslatorRoster* roster = BTranslatorRoster::Default();
roster->StopWatching(this);
}
// Reads the installed translators and adds them to our BListView
status_t
DataTranslationsWindow::_PopulateListView()
{
BTranslatorRoster* roster = BTranslatorRoster::Default();
// Get all Translators on the system. Gives us the number of translators
// installed in num_translators and a reference to the first one
int32 numTranslators;
translator_id* translators = NULL;
roster->GetAllTranslators(&translators, &numTranslators);
float maxWidth = 0;
for (int32 i = 0; i < numTranslators; i++) {
// Getting the first three Infos: Name, Info & Version
int32 version;
const char* name;
const char* info;
roster->GetTranslatorInfo(translators[i], &name, &info, &version);
fTranslatorListView->AddItem(new TranslatorItem(translators[i], name));
maxWidth = std::max(maxWidth, fTranslatorListView->StringWidth(name));
}
fTranslatorListView->SortItems();
fTranslatorListView->SetExplicitSize(BSize(maxWidth + 20, B_SIZE_UNSET));
delete[] translators;
return B_OK;
}
status_t
DataTranslationsWindow::_GetTranslatorInfo(int32 id, const char*& name,
const char*& info, int32& version, BPath& path)
{
// Returns information about the translator with the given id
if (id < 0)
return B_BAD_VALUE;
BTranslatorRoster* roster = BTranslatorRoster::Default();
if (roster->GetTranslatorInfo(id, &name, &info, &version) != B_OK)
return B_ERROR;
// Get the translator's path
entry_ref ref;
if (roster->GetRefFor(id, &ref) == B_OK) {
BEntry entry(&ref);
path.SetTo(&entry);
} else
path.Unset();
return B_OK;
}
status_t
DataTranslationsWindow::_ShowConfigView(int32 id)
{
// Shows the config panel for the translator with the given id
if (id < 0)
return B_BAD_VALUE;
BTranslatorRoster* roster = BTranslatorRoster::Default();
if (fConfigView != NULL) {
fRightBox->RemoveChild(fConfigView);
delete fConfigView;
fConfigView = NULL;
fInfoText = NULL;
if (fRelease != NULL) {
fRelease->Release();
fRelease = NULL;
}
}
BMessage emptyMessage;
BRect rect(0.0f, 0.0f, 200.0f, 233.0f);
status_t result = roster->MakeConfigurationView(id, &emptyMessage,
&fConfigView, &rect);
if (result != B_OK)
return result;
fConfigView->SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
// force config views to all have the same color
fRightBox->AddChild(fConfigView);
// for default 12pt font size: 597 ≈ (0.85 * 12 * 49)
fConfigView->SetExplicitMinSize(
BSize(ceilf(be_control_look->DefaultItemSpacing() * 49)
- fTranslatorListView->Frame().Width(), B_SIZE_UNSET));
// Make sure the translator's image doesn't get unloaded while we are still
// showing a config view whose code is in the image
fRelease = roster->AcquireTranslator(id);
return B_OK;
}
void
DataTranslationsWindow::_ShowInfoView()
{
if (fConfigView != NULL) {
fRightBox->RemoveChild(fConfigView);
delete fConfigView;
fConfigView = NULL;
fInfoText = NULL;
if (fRelease != NULL) {
fRelease->Release();
fRelease = NULL;
}
}
fInfoText = new BTextView("info text");
fInfoText->MakeEditable(false);
fInfoText->MakeSelectable(false);
fInfoText->SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
fInfoText->SetText(B_TRANSLATE(
"Use this control panel to set default values for translators, "
"to be used when no other settings are specified by an application."));
rgb_color textColor = ui_color(B_PANEL_TEXT_COLOR);
fInfoText->SetFontAndColor(be_plain_font, B_FONT_ALL, &textColor);
BGroupView* group = new BGroupView(B_VERTICAL);
group->AddChild(fInfoText);
float spacing = be_control_look->DefaultItemSpacing();
group->GroupLayout()->SetInsets(spacing, spacing, spacing, spacing);
fRightBox->AddChild(group);
fConfigView = group;
fConfigView->SetExplicitMinSize(
BSize(ceilf(spacing * be_plain_font->Size() * 0.7)
- fTranslatorListView->Frame().Width(),
ceilf(spacing * be_plain_font->Size() * 0.4)));
}
void
DataTranslationsWindow::_SetupViews()
{
fInfoText = NULL;
fConfigView = NULL;
// This is NULL until a translator is
// selected from the listview
// Add the translators list view
fTranslatorListView = new TranslatorListView("TransList");
fTranslatorListView->SetSelectionMessage(
new BMessage(kMsgSelectedTranslator));
BScrollView* scrollView = new BScrollView("scroll_trans",
fTranslatorListView, B_WILL_DRAW | B_FRAME_EVENTS, false,
true, B_FANCY_BORDER);
// Box around the config and info panels
fRightBox = new BBox("Right_Side");
fRightBox->SetExplicitAlignment(BAlignment(B_ALIGN_USE_FULL_WIDTH,
B_ALIGN_USE_FULL_HEIGHT));
// Add the translator icon view
fIconView = new IconView();
// Add the translator info button
fButton = new BButton("info", B_TRANSLATE("Info"),
new BMessage(kMsgTranslatorInfo),
B_WILL_DRAW | B_FRAME_EVENTS | B_NAVIGABLE);
fButton->SetEnabled(false);
// Populate the translators list view
_PopulateListView();
// Build the layout
BLayoutBuilder::Group<>(this, B_HORIZONTAL)
.SetInsets(B_USE_WINDOW_SPACING)
.Add(scrollView, 3)
.AddGroup(B_VERTICAL)
.Add(fRightBox)
.AddGroup(B_HORIZONTAL)
.Add(fIconView)
.AddGlue()
.Add(fButton)
.End()
.End()
.End();
fTranslatorListView->MakeFocus();
_ShowInfoView();
}
bool
DataTranslationsWindow::QuitRequested()
{
BPoint pt(Frame().LeftTop());
DataTranslationsSettings::Instance()->SetWindowCorner(pt);
be_app->PostMessage(B_QUIT_REQUESTED);
return true;
}
void
DataTranslationsWindow::_ShowInfoAlert(int32 id)
{
const char* name = NULL;
const char* info = NULL;
BPath path;
int32 version = 0;
_GetTranslatorInfo(id, name, info, version, path);
const char* labels[] = { B_TRANSLATE("Name:"), B_TRANSLATE("Version:"),
B_TRANSLATE("Info:"), B_TRANSLATE("Path:"), NULL };
int offsets[4];
BString message;
BString temp;
offsets[0] = 0;
temp.SetToFormat("%s %s\n", labels[0], name);
message.Append(temp);
offsets[1] = message.Length();
// Convert the version number into a readable format
temp.SetToFormat("%s %" B_PRId32 ".%" B_PRId32 ".%" B_PRId32 "\n\n", labels[1],
B_TRANSLATION_MAJOR_VERSION(version),
B_TRANSLATION_MINOR_VERSION(version),
B_TRANSLATION_REVISION_VERSION(version));
message.Append(temp);
offsets[2] = message.Length();
temp.SetToFormat("%s\n%s\n\n", labels[2], info);
message.Append(temp);
offsets[3] = message.Length();
temp.SetToFormat("%s %s\n", labels[3], path.Path());
message.Append(temp);
BAlert* alert = new BAlert(B_TRANSLATE("Info"), message.String(),
B_TRANSLATE("OK"));
BTextView* view = alert->TextView();
BFont font;
view->SetStylable(true);
view->GetFont(&font);
font.SetFace(B_BOLD_FACE);
for (int32 i = 0; labels[i]; i++) {
view->SetFontAndColor(offsets[i], offsets[i] + strlen(labels[i]), &font);
}
alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
alert->Go();
}
void
DataTranslationsWindow::MessageReceived(BMessage* message)
{
switch (message->what) {
case kMsgTranslatorInfo:
{
int32 selected = fTranslatorListView->CurrentSelection(0);
if (selected < 0)
break;
TranslatorItem* item = fTranslatorListView->TranslatorAt(selected);
if (item != NULL)
_ShowInfoAlert(item->ID());
break;
}
case kMsgSelectedTranslator:
{
// Update the icon and translator info panel
// to match the new selection
int32 selected = fTranslatorListView->CurrentSelection(0);
if (selected < 0) {
// If none selected, clear the old one
fIconView->DrawIcon(false);
fButton->SetEnabled(false);
fRightBox->RemoveChild(fConfigView);
_ShowInfoView();
break;
}
TranslatorItem* item = fTranslatorListView->TranslatorAt(selected);
if (item == NULL)
break;
_ShowConfigView(item->ID());
const char* name = NULL;
const char* info = NULL;
int32 version = 0;
BPath path;
_GetTranslatorInfo(item->ID(), name, info, version, path);
fIconView->SetIcon(path);
fButton->SetEnabled(true);
break;
}
case B_COLORS_UPDATED:
{
if (fInfoText == NULL || fInfoText->Parent() == NULL)
break;
rgb_color color;
if (message->FindColor(ui_color_name(B_PANEL_TEXT_COLOR), &color)
== B_OK) {
fInfoText->SetFontAndColor(be_plain_font, B_FONT_ALL, &color);
}
break;
}
case B_TRANSLATOR_ADDED:
{
int32 index = 0;
int32 id;
while (message->FindInt32("translator_id", index++, &id) == B_OK) {
const char* name;
const char* info;
int32 version;
BPath path;
if (_GetTranslatorInfo(id, name, info, version, path) == B_OK)
fTranslatorListView->AddItem(new TranslatorItem(id, name));
}
fTranslatorListView->SortItems();
break;
}
case B_TRANSLATOR_REMOVED:
{
int32 index = 0;
int32 id;
while (message->FindInt32("translator_id", index++, &id) == B_OK) {
for (int32 i = 0; i < fTranslatorListView->CountItems(); i++) {
TranslatorItem* item = fTranslatorListView->TranslatorAt(i);
if (item == NULL)
continue;
if (item->ID() == (translator_id)id) {
fTranslatorListView->RemoveItem(i);
delete item;
break;
}
}
}
break;
}
default:
BWindow::MessageReceived(message);
break;
}
}
↑ V773 Visibility scope of the 'alert' pointer was exited without releasing the memory. A memory leak is possible.