/*
* Copyright 2006-2007, Axel Dörfler, axeld@pinc-software.de.
* All rights reserved. Distributed under the terms of the MIT License.
*/
#include "ApplicationTypesWindow.h"
#include "ApplicationTypeWindow.h"
#include "FileTypes.h"
#include "FileTypesWindow.h"
#include "FileTypeWindow.h"
#include <AppFileInfo.h>
#include <Application.h>
#include <Alert.h>
#include <Catalog.h>
#include <Locale.h>
#include <TextView.h>
#include <FilePanel.h>
#include <FindDirectory.h>
#include <Directory.h>
#include <Entry.h>
#include <Path.h>
#include <Resources.h>
#include <stdio.h>
#include <strings.h>
#undef B_TRANSLATION_CONTEXT
#define B_TRANSLATION_CONTEXT "FileTypes"
const char* kSignature = "application/x-vnd.Haiku-FileTypes";
static const uint32 kMsgFileTypesSettings = 'FTst';
static const uint32 kCascadeOffset = 20;
class Settings {
public:
Settings();
~Settings();
const BMessage& Message() const { return fMessage; }
void UpdateFrom(BMessage* message);
private:
void _SetDefaults();
status_t _Open(BFile* file, int32 mode);
BMessage fMessage;
bool fUpdated;
};
class FileTypes : public BApplication {
public:
FileTypes();
virtual ~FileTypes();
virtual void ReadyToRun();
virtual void RefsReceived(BMessage* message);
virtual void ArgvReceived(int32 argc, char** argv);
virtual void MessageReceived(BMessage* message);
virtual bool QuitRequested();
private:
void _WindowClosed();
Settings fSettings;
BFilePanel* fFilePanel;
BMessenger fFilePanelTarget;
FileTypesWindow* fTypesWindow;
BWindow* fApplicationTypesWindow;
uint32 fWindowCount;
uint32 fTypeWindowCount;
BString fArgvType;
};
Settings::Settings()
:
fMessage(kMsgFileTypesSettings),
fUpdated(false)
{
_SetDefaults();
BFile file;
if (_Open(&file, B_READ_ONLY) != B_OK)
return;
BMessage settings;
if (settings.Unflatten(&file) == B_OK) {
// We don't unflatten into our default message to make sure
// nothing is lost (because of old or corrupted on disk settings)
UpdateFrom(&settings);
fUpdated = false;
}
}
Settings::~Settings()
{
// only save the settings if something has changed
if (!fUpdated)
return;
BFile file;
if (_Open(&file, B_CREATE_FILE | B_ERASE_FILE | B_WRITE_ONLY) != B_OK)
return;
fMessage.Flatten(&file);
}
void
Settings::UpdateFrom(BMessage* message)
{
BRect frame;
if (message->FindRect("file_types_frame", &frame) == B_OK)
fMessage.ReplaceRect("file_types_frame", frame);
if (message->FindRect("app_types_frame", &frame) == B_OK)
fMessage.ReplaceRect("app_types_frame", frame);
bool showIcons;
if (message->FindBool("show_icons", &showIcons) == B_OK)
fMessage.ReplaceBool("show_icons", showIcons);
bool showRule;
if (message->FindBool("show_rule", &showRule) == B_OK)
fMessage.ReplaceBool("show_rule", showRule);
float splitWeight;
if (message->FindFloat("left_split_weight", &splitWeight) == B_OK)
fMessage.ReplaceFloat("left_split_weight", splitWeight);
if (message->FindFloat("right_split_weight", &splitWeight) == B_OK)
fMessage.ReplaceFloat("right_split_weight", splitWeight);
fUpdated = true;
}
void
Settings::_SetDefaults()
{
fMessage.AddRect("file_types_frame", BRect(80.0f, 80.0f, 600.0f, 480.0f));
fMessage.AddRect("app_types_frame", BRect(100.0f, 100.0f, 540.0f, 480.0f));
fMessage.AddBool("show_icons", true);
fMessage.AddBool("show_rule", false);
fMessage.AddFloat("left_split_weight", 0.2);
fMessage.AddFloat("right_split_weight", 0.8);
}
status_t
Settings::_Open(BFile* file, int32 mode)
{
BPath path;
if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) != B_OK)
return B_ERROR;
path.Append("FileTypes settings");
return file->SetTo(path.Path(), mode);
}
// #pragma mark -
FileTypes::FileTypes()
:
BApplication(kSignature),
fTypesWindow(NULL),
fApplicationTypesWindow(NULL),
fWindowCount(0),
fTypeWindowCount(0)
{
fFilePanel = new BFilePanel(B_OPEN_PANEL, NULL, NULL,
B_FILE_NODE, false);
}
FileTypes::~FileTypes()
{
delete fFilePanel;
}
void
FileTypes::ReadyToRun()
{
// are there already windows open?
if (CountWindows() != 1)
return;
// if not, open the FileTypes window
PostMessage(kMsgOpenTypesWindow);
}
void
FileTypes::RefsReceived(BMessage* message)
{
bool traverseLinks = (modifiers() & B_SHIFT_KEY) == 0;
// filter out applications and entries we can't open
int32 index = 0;
entry_ref ref;
while (message->FindRef("refs", index++, &ref) == B_OK) {
BEntry entry;
BFile file;
status_t status = entry.SetTo(&ref, traverseLinks);
if (status == B_OK)
status = file.SetTo(&entry, B_READ_ONLY);
if (status != B_OK) {
// file cannot be opened
char buffer[1024];
snprintf(buffer, sizeof(buffer),
B_TRANSLATE("Could not open \"%s\":\n"
"%s"),
ref.name, strerror(status));
BAlert* alert = new BAlert(B_TRANSLATE("FileTypes request"),
buffer, B_TRANSLATE("OK"), NULL, NULL,
B_WIDTH_AS_USUAL, B_STOP_ALERT);
alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
alert->Go();
message->RemoveData("refs", --index);
continue;
}
if (!is_application(file) && !is_resource(file)) {
entry_ref target;
if (entry.GetRef(&target) == B_OK && target != ref)
message->ReplaceRef("refs", index - 1, &ref);
continue;
}
// remove application from list
message->RemoveData("refs", --index);
// There are some refs left that want to be handled by the type window
BPoint point(100.0f + kCascadeOffset * fTypeWindowCount,
110.0f + kCascadeOffset * fTypeWindowCount);
BWindow* window = new ApplicationTypeWindow(point, entry);
window->Show();
fTypeWindowCount++;
fWindowCount++;
}
if (message->FindRef("refs", &ref) != B_OK)
return;
// There are some refs left that want to be handled by the type window
BPoint point(100.0f + kCascadeOffset * fTypeWindowCount,
110.0f + kCascadeOffset * fTypeWindowCount);
BWindow* window = new FileTypeWindow(point, *message);
window->Show();
fTypeWindowCount++;
fWindowCount++;
}
void
FileTypes::ArgvReceived(int32 argc, char** argv)
{
if (argc == 3 && strcmp(argv[1], "-type") == 0) {
fArgvType = argv[2];
return;
}
BMessage* message = CurrentMessage();
BDirectory currentDirectory;
if (message != NULL)
currentDirectory.SetTo(message->FindString("cwd"));
BMessage refs;
for (int i = 1 ; i < argc ; i++) {
BPath path;
if (argv[i][0] == '/')
path.SetTo(argv[i]);
else
path.SetTo(¤tDirectory, argv[i]);
status_t status;
entry_ref ref;
BEntry entry;
if ((status = entry.SetTo(path.Path(), false)) != B_OK
|| (status = entry.GetRef(&ref)) != B_OK) {
fprintf(stderr, "Could not open file \"%s\": %s\n",
path.Path(), strerror(status));
continue;
}
refs.AddRef("refs", &ref);
}
RefsReceived(&refs);
}
void
FileTypes::MessageReceived(BMessage* message)
{
switch (message->what) {
case kMsgSettingsChanged:
fSettings.UpdateFrom(message);
break;
case kMsgOpenTypesWindow:
if (fTypesWindow == NULL) {
fTypesWindow = new FileTypesWindow(fSettings.Message());
if (fArgvType.Length() > 0) {
// Set the window to the type that was requested on the
// command line (-type), we do this only once, if we
// ever opened more than one FileTypesWindow.
fTypesWindow->SelectType(fArgvType.String());
fArgvType = "";
}
fTypesWindow->Show();
fWindowCount++;
} else
fTypesWindow->Activate(true);
break;
case kMsgTypesWindowClosed:
fTypesWindow = NULL;
_WindowClosed();
break;
case kMsgOpenApplicationTypesWindow:
if (fApplicationTypesWindow == NULL) {
fApplicationTypesWindow = new ApplicationTypesWindow(
fSettings.Message());
fApplicationTypesWindow->Show();
fWindowCount++;
} else
fApplicationTypesWindow->Activate(true);
break;
case kMsgApplicationTypesWindowClosed:
fApplicationTypesWindow = NULL;
_WindowClosed();
break;
case kMsgTypeWindowClosed:
fTypeWindowCount--;
// supposed to fall through
case kMsgWindowClosed:
_WindowClosed();
break;
case kMsgOpenFilePanel:
{
// the open file panel sends us a message when it's done
const char* subTitle;
if (message->FindString("title", &subTitle) != B_OK)
subTitle = B_TRANSLATE("Open file");
int32 what;
if (message->FindInt32("message", &what) != B_OK)
what = B_REFS_RECEIVED;
BMessenger target;
if (message->FindMessenger("target", &target) != B_OK)
target = be_app_messenger;
BString title = B_TRANSLATE("FileTypes");
if (subTitle != NULL && subTitle[0]) {
title.Append(": ");
title.Append(subTitle);
}
uint32 flavors = B_FILE_NODE;
if (message->FindBool("allowDirs"))
flavors |= B_DIRECTORY_NODE;
fFilePanel->SetNodeFlavors(flavors);
fFilePanel->SetMessage(new BMessage(what));
fFilePanel->Window()->SetTitle(title.String());
fFilePanel->SetTarget(target);
if (!fFilePanel->IsShowing())
fFilePanel->Show();
break;
}
case B_SILENT_RELAUNCH:
// In case we were launched via the add-on, there is no types
// window yet.
if (fTypesWindow == NULL)
PostMessage(kMsgOpenTypesWindow);
break;
case B_CANCEL:
if (fWindowCount == 0)
PostMessage(B_QUIT_REQUESTED);
break;
case B_SIMPLE_DATA:
RefsReceived(message);
break;
default:
BApplication::MessageReceived(message);
break;
}
}
bool
FileTypes::QuitRequested()
{
return true;
}
void
FileTypes::_WindowClosed()
{
if (--fWindowCount == 0 && !fFilePanel->IsShowing())
PostMessage(B_QUIT_REQUESTED);
}
// #pragma mark -
bool
is_application(BFile& file)
{
BAppFileInfo appInfo(&file);
if (appInfo.InitCheck() != B_OK)
return false;
char type[B_MIME_TYPE_LENGTH];
if (appInfo.GetType(type) != B_OK
|| strcasecmp(type, B_APP_MIME_TYPE))
return false;
return true;
}
bool
is_resource(BFile& file)
{
BResources resources(&file);
if (resources.InitCheck() != B_OK)
return false;
BNodeInfo nodeInfo(&file);
char type[B_MIME_TYPE_LENGTH];
if (nodeInfo.GetType(type) != B_OK
|| strcasecmp(type, B_RESOURCE_MIME_TYPE))
return false;
return true;
}
void
error_alert(const char* message, status_t status, alert_type type)
{
char warning[512];
if (status != B_OK) {
snprintf(warning, sizeof(warning), "%s:\n\t%s\n", message,
strerror(status));
}
BAlert* alert = new BAlert(B_TRANSLATE("FileTypes request"),
status == B_OK ? message : warning,
B_TRANSLATE("OK"), NULL, NULL, B_WIDTH_AS_USUAL, type);
alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
alert->Go();
}
int
main(int argc, char** argv)
{
FileTypes probe;
probe.Run();
return 0;
}
↑ V773 Visibility scope of the 'alert' pointer was exited without releasing the memory. A memory leak is possible.