More work on FileTypes:

* You can now edit and add extensions.
* The internal name view is no longer a disabled BTextControl, but a simple
  customized BStringView like view.
* New "Application Types" window in the making.
* MimeTypeListView can now have icons and supports a flat mode as well
  as an application only mode.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@16405 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler 2006-02-15 15:48:35 +00:00
parent c432fbbbb7
commit 041ea26008
15 changed files with 1102 additions and 75 deletions

View File

@ -0,0 +1,329 @@
/*
* Copyright 2006, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
* Distributed under the terms of the MIT License.
*/
// TODO: think about adopting Tracker's info window style here (pressable path)
#include "ApplicationTypesWindow.h"
#include "FileTypes.h"
#include "FileTypesWindow.h"
#include "MimeTypeListView.h"
#include "StringView.h"
#include <AppFileInfo.h>
#include <Application.h>
#include <Bitmap.h>
#include <Box.h>
#include <Button.h>
#include <MenuField.h>
#include <MenuItem.h>
#include <Mime.h>
#include <NodeInfo.h>
#include <Path.h>
#include <PopUpMenu.h>
#include <Query.h>
#include <Roster.h>
#include <ScrollView.h>
#include <StringView.h>
#include <Volume.h>
#include <VolumeRoster.h>
#include <stdio.h>
const uint32 kMsgTypeSelected = 'typs';
const uint32 kMsgRemoveUninstalled = 'runs';
ApplicationTypesWindow::ApplicationTypesWindow(BRect frame)
: BWindow(frame, "Application Types", B_TITLED_WINDOW,
B_NOT_ZOOMABLE | B_ASYNCHRONOUS_CONTROLS)
{
// Application list
BRect rect = Bounds();
BView* topView = new BView(rect, NULL, B_FOLLOW_ALL, B_WILL_DRAW);
topView->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
AddChild(topView);
BButton* button = new BButton(rect, "remove", "Remove Uninstalled",
new BMessage(kMsgRemoveUninstalled), B_FOLLOW_LEFT | B_FOLLOW_BOTTOM);
button->ResizeToPreferred();
button->MoveTo(8.0f, rect.bottom - 8.0f - button->Bounds().Height());
topView->AddChild(button);
rect.bottom = button->Frame().top - 10.0f;
rect.top = 10.0f;
rect.left = 10.0f;
rect.right = 170;
fTypeListView = new MimeTypeListView(rect, "listview", "application", true, true,
B_FOLLOW_LEFT | B_FOLLOW_TOP_BOTTOM);
fTypeListView->SetSelectionMessage(new BMessage(kMsgTypeSelected));
BScrollView* scrollView = new BScrollView("scrollview", fTypeListView,
B_FOLLOW_LEFT | B_FOLLOW_TOP_BOTTOM, B_FRAME_EVENTS | B_WILL_DRAW, false, true);
topView->AddChild(scrollView);
// "Description" group
BFont font(be_bold_font);
float labelWidth = font.StringWidth("Icon");
font_height fontHeight;
font.GetHeight(&fontHeight);
rect.left = rect.right + 12.0f + B_V_SCROLL_BAR_WIDTH;
rect.top -= 2.0f;
rect.right = topView->Bounds().Width() - 8.0f;
rect.bottom = rect.top + ceilf(fontHeight.ascent) + 24.0f;
BBox* box = new BBox(rect, NULL, B_FOLLOW_LEFT_RIGHT);
box->SetLabel("Description");
topView->AddChild(box);
BRect innerRect = box->Bounds().InsetByCopy(8.0f, 6.0f);
labelWidth = topView->StringWidth("Signature:") + 4.0f;
innerRect.right = box->Bounds().Width() - 8.0f;
innerRect.top += ceilf(fontHeight.ascent);
fNameView = new StringView(innerRect, "name", "Name:", NULL, B_FOLLOW_LEFT_RIGHT);
fNameView->SetDivider(labelWidth);
float width, height;
fNameView->GetPreferredSize(&width, &height);
fNameView->ResizeTo(innerRect.Width(), height);
box->ResizeBy(0, fNameView->Bounds().Height() * 3.0f);
box->AddChild(fNameView);
innerRect.OffsetBy(0, fNameView->Bounds().Height() + 5.0f);
fSignatureView = new StringView(innerRect, "signature", "Signature:", NULL,
B_FOLLOW_LEFT_RIGHT);
fSignatureView->SetDivider(labelWidth);
box->AddChild(fSignatureView);
innerRect.OffsetBy(0, fNameView->Bounds().Height() + 5.0f);
fPathView = new StringView(innerRect, "path", "Path:", NULL,
B_FOLLOW_LEFT_RIGHT);
fPathView->SetDivider(labelWidth);
box->AddChild(fPathView);
// Launch and Tracker buttons
rect = box->Frame();
rect.top = rect.bottom + 8.0f;
rect.bottom = rect.top + 20.0f;
fTrackerButton = new BButton(rect, "tracker", "Open In Tracker" B_UTF8_ELLIPSIS, NULL,
B_FOLLOW_RIGHT);
fTrackerButton->ResizeToPreferred();
fTrackerButton->MoveTo(rect.right - fTrackerButton->Bounds().Width(), rect.top);
topView->AddChild(fTrackerButton);
fLaunchButton = new BButton(rect, "launch", "Launch", NULL,
B_FOLLOW_RIGHT);
fLaunchButton->ResizeToPreferred();
fLaunchButton->MoveTo(fTrackerButton->Frame().left - 6.0f
- fLaunchButton->Bounds().Width(), rect.top);
topView->AddChild(fLaunchButton);
SetSizeLimits(scrollView->Frame().right + 22.0f + fTrackerButton->Frame().Width()
+ fLaunchButton->Frame().Width(), 32767.0f,
fTrackerButton->Frame().bottom + 8.0f, 32767.0f);
BMimeType::StartWatching(this);
_SetType(NULL);
}
ApplicationTypesWindow::~ApplicationTypesWindow()
{
BMimeType::StopWatching(this);
}
void
ApplicationTypesWindow::_RemoveUninstalled()
{
// Note: this runs in the looper's thread, which isn't that nice
int32 removed = 0;
for (int32 i = fTypeListView->FullListCountItems(); i-- > 0;) {
MimeTypeItem* item = dynamic_cast<MimeTypeItem*>(fTypeListView->FullListItemAt(i));
if (item == NULL)
continue;
// search for application on all volumes
bool found = false;
BVolumeRoster volumeRoster;
BVolume volume;
while (volumeRoster.GetNextVolume(&volume) == B_OK) {
if (!volume.KnowsQuery())
continue;
BQuery query;
query.PushAttr("BEOS:APP_SIG");
query.PushString(item->Type());
query.PushOp(B_EQ);
query.SetVolume(&volume);
query.Fetch();
entry_ref ref;
if (query.GetNextRef(&ref) == B_OK) {
found = true;
break;
}
}
if (!found) {
BMimeType mimeType(item->Type());
mimeType.Delete();
removed++;
// We're blocking the message loop that received the MIME changes,
// so we dequeue all waiting messages from time to time
if (removed % 10 == 0)
UpdateIfNeeded();
}
}
char message[512];
snprintf(message, sizeof(message), "%ld Application Type%s could be removed.",
removed, removed == 1 ? "" : "s");
error_alert(message, B_OK, B_INFO_ALERT);
}
void
ApplicationTypesWindow::_SetType(BMimeType* type, int32 forceUpdate)
{
bool enabled = type != NULL;
bool appFound = true;
// update controls
if (type != NULL) {
if (fCurrentType == *type) {
if (!forceUpdate)
return;
} else
forceUpdate = B_EVERYTHING_CHANGED;
if (&fCurrentType != type)
fCurrentType.SetTo(type->Type());
fSignatureView->SetText(type->Type());
char description[B_MIME_TYPE_LENGTH];
if ((forceUpdate & B_SHORT_DESCRIPTION_CHANGED) != 0) {
if (type->GetShortDescription(description) != B_OK)
description[0] = '\0';
fNameView->SetText(description);
}
entry_ref ref;
// TODO: disabled because of somewhat broken BRoster::FindApp() behaviour
if (/*(forceUpdate & B_APP_HINT_CHANGED) != 0*/
forceUpdate == B_EVERYTHING_CHANGED
&& be_roster->FindApp(fCurrentType.Type(), &ref) == B_OK) {
// Set launch message
BMessenger tracker("application/x-vnd.Be-TRAK");
BMessage* message = new BMessage(B_REFS_RECEIVED);
message->AddRef("refs", &ref);
fLaunchButton->SetMessage(message);
fLaunchButton->SetTarget(tracker);
// Set path
BPath path(&ref);
path.GetParent(&path);
fPathView->SetText(path.Path());
// Set "Open In Tracker" message
BEntry entry(path.Path());
if (entry.GetRef(&ref) == B_OK) {
BMessenger tracker("application/x-vnd.Be-TRAK");
message = new BMessage(B_REFS_RECEIVED);
message->AddRef("refs", &ref);
fTrackerButton->SetMessage(message);
fTrackerButton->SetTarget(tracker);
} else {
fTrackerButton->SetMessage(NULL);
appFound = false;
}
}
} else {
fNameView->SetText(NULL);
fNameView->SetText(NULL);
fPathView->SetText(NULL);
}
fNameView->SetEnabled(enabled);
fSignatureView->SetEnabled(enabled);
fPathView->SetEnabled(enabled);
fTrackerButton->SetEnabled(enabled && appFound);
fLaunchButton->SetEnabled(enabled && appFound);
}
void
ApplicationTypesWindow::MessageReceived(BMessage* message)
{
switch (message->what) {
case kMsgTypeSelected:
{
int32 index;
if (message->FindInt32("index", &index) == B_OK) {
MimeTypeItem* item = (MimeTypeItem*)fTypeListView->ItemAt(index);
if (item != NULL) {
BMimeType type(item->Type());
_SetType(&type);
} else
_SetType(NULL);
}
break;
}
case kMsgRemoveUninstalled:
_RemoveUninstalled();
break;
case B_META_MIME_CHANGED:
{
const char* type;
int32 which;
if (message->FindString("be:type", &type) != B_OK
|| message->FindInt32("be:which", &which) != B_OK)
break;
if (fCurrentType.Type() == NULL)
break;
if (!strcasecmp(fCurrentType.Type(), type)) {
if (which != B_MIME_TYPE_DELETED)
_SetType(&fCurrentType, which);
else
_SetType(NULL);
}
break;
}
default:
BWindow::MessageReceived(message);
}
}
bool
ApplicationTypesWindow::QuitRequested()
{
be_app->PostMessage(kMsgApplicationTypesWindowClosed);
return true;
}

View File

@ -0,0 +1,51 @@
/*
* Copyright 2006, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
* Distributed under the terms of the MIT License.
*/
#ifndef APPLICATION_TYPES_WINDOW_H
#define APPLICATION_TYPES_WINDOW_H
#include <Alert.h>
#include <Mime.h>
#include <Window.h>
class BButton;
class BListView;
class BMenuField;
class BMimeType;
class BOutlineListView;
class BStringView;
class MimeTypeListView;
class StringView;
class ApplicationTypesWindow : public BWindow {
public:
ApplicationTypesWindow(BRect frame);
virtual ~ApplicationTypesWindow();
virtual void MessageReceived(BMessage* message);
virtual bool QuitRequested();
private:
void _SetType(BMimeType* type, int32 forceUpdate = 0);
void _UpdateCounter();
void _RemoveUninstalled();
private:
BMimeType fCurrentType;
MimeTypeListView* fTypeListView;
BButton* fRemoveTypeButton;
StringView* fNameView;
StringView* fSignatureView;
StringView* fPathView;
BButton* fTrackerButton;
BButton* fLaunchButton;
};
#endif // APPLICATION_TYPES_WINDOW_H

View File

@ -0,0 +1,186 @@
/*
* Copyright 2006, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
* Distributed under the terms of the MIT License.
*/
#include "ExtensionWindow.h"
#include "FileTypesWindow.h"
#include <Button.h>
#include <MenuField.h>
#include <MenuItem.h>
#include <Mime.h>
#include <PopUpMenu.h>
#include <String.h>
#include <TextControl.h>
#include <string.h>
const uint32 kMsgExtensionUpdated = 'exup';
const uint32 kMsgAccept = 'acpt';
static int
compare_extensions(const void* _a, const void* _b)
{
const char* a = *(const char **)_a;
const char* b = *(const char **)_b;
int compare = strcasecmp(a, b);
if (compare != 0)
return compare;
// sort lower case characters first
return -strcmp(a, b);
}
// #pragma mark -
ExtensionWindow::ExtensionWindow(FileTypesWindow* target, BMimeType& type,
const char* extension)
: BWindow(BRect(100, 100, 350, 200), "Extension", B_MODAL_WINDOW_LOOK,
B_MODAL_SUBSET_WINDOW_FEEL, B_NOT_ZOOMABLE | B_NOT_V_RESIZABLE
| B_ASYNCHRONOUS_CONTROLS),
fTarget(target),
fMimeType(type.Type()),
fExtension(extension)
{
BRect rect = Bounds();
BView* topView = new BView(rect, NULL, B_FOLLOW_ALL, B_WILL_DRAW);
topView->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
AddChild(topView);
rect.InsetBy(8.0f, 8.0f);
fExtensionControl = new BTextControl(rect, "extension", "Extension:", extension,
NULL, B_FOLLOW_LEFT_RIGHT);
float labelWidth = fExtensionControl->StringWidth(fExtensionControl->Label()) + 2.0f;
fExtensionControl->SetModificationMessage(new BMessage(kMsgExtensionUpdated));
fExtensionControl->SetDivider(labelWidth);
fExtensionControl->SetAlignment(B_ALIGN_RIGHT, B_ALIGN_LEFT);
// filter out invalid characters that can't be part of an extension
BTextView* textView = fExtensionControl->TextView();
const char* disallowedCharacters = "/:";
for (int32 i = 0; disallowedCharacters[i]; i++) {
textView->DisallowChar(disallowedCharacters[i]);
}
float width, height;
fExtensionControl->GetPreferredSize(&width, &height);
fExtensionControl->ResizeTo(rect.Width(), height);
topView->AddChild(fExtensionControl);
fAcceptButton = new BButton(rect, "add", extension ? "Done" : "Add",
new BMessage(kMsgAccept), B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM);
fAcceptButton->ResizeToPreferred();
fAcceptButton->MoveTo(Bounds().Width() - 8.0f - fAcceptButton->Bounds().Width(),
Bounds().Height() - 8.0f - fAcceptButton->Bounds().Height());
fAcceptButton->SetEnabled(false);
topView->AddChild(fAcceptButton);
BButton* button = new BButton(rect, "cancel", "Cancel",
new BMessage(B_QUIT_REQUESTED), B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM);
button->ResizeToPreferred();
button->MoveTo(fAcceptButton->Frame().left - 10.0f - button->Bounds().Width(),
fAcceptButton->Frame().top);
topView->AddChild(button);
ResizeTo(labelWidth * 4.0f + 24.0f, fExtensionControl->Bounds().Height() * 2.0f + 30.0f);
SetSizeLimits(button->Bounds().Width() + fAcceptButton->Bounds().Width() + 26.0f,
32767.0f, Frame().Height(), Frame().Height());
// omit the leading dot
if (fExtension.ByteAt(0) == '.')
fExtension.Remove(0, 1);
fAcceptButton->MakeDefault(true);
fExtensionControl->MakeFocus(true);
target->PlaceSubWindow(this);
AddToSubset(target);
}
ExtensionWindow::~ExtensionWindow()
{
}
void
ExtensionWindow::MessageReceived(BMessage* message)
{
switch (message->what) {
case kMsgExtensionUpdated:
{
bool enabled = fExtensionControl->Text() != NULL
&& fExtensionControl->Text()[0] != '\0';
if (enabled) {
// There is some text, but we only accept it, if it
// changed the previous extension
enabled = strcmp(fExtensionControl->Text(), fExtension.String());
}
if (fAcceptButton->IsEnabled() != enabled)
fAcceptButton->SetEnabled(enabled);
break;
}
case kMsgAccept:
{
const char* newExtension = fExtensionControl->Text();
// omit the leading dot
if (newExtension[0] == '.')
newExtension++;
BMessage extensions;
status_t status = fMimeType.GetFileExtensions(&extensions);
if (status == B_OK) {
// replace the entry, and remove any equivalent entries
BList list;
list.AddItem((void *)newExtension);
const char* extension;
for (int32 i = 0; extensions.FindString("extensions", i,
&extension) == B_OK; i++) {
if (!strcmp(fExtension.String(), extension)
|| !strcmp(newExtension, extension)) {
// remove this item
continue;
}
list.AddItem((void *)extension);
}
list.SortItems(compare_extensions);
// Copy them to a new message (their memory is still part of the
// original BMessage)
BMessage newExtensions;
for (int32 i = 0; i < list.CountItems(); i++) {
newExtensions.AddString("extensions", (const char*)list.ItemAt(i));
}
status = fMimeType.SetFileExtensions(&newExtensions);
}
if (status != B_OK)
error_alert("Could not change file extensions", status);
PostMessage(B_QUIT_REQUESTED);
break;
}
}
}
bool
ExtensionWindow::QuitRequested()
{
fTarget.SendMessage(kMsgNewTypeWindowClosed);
return true;
}

View File

@ -0,0 +1,36 @@
/*
* Copyright 2006, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
* Distributed under the terms of the MIT License.
*/
#ifndef EXTENSION_WINDOW_H
#define EXTENSION_WINDOW_H
#include <Messenger.h>
#include <Mime.h>
#include <String.h>
#include <Window.h>
class BButton;
class BTextControl;
class FileTypesWindow;
class ExtensionWindow : public BWindow {
public:
ExtensionWindow(FileTypesWindow* target, BMimeType& type, const char* extension);
virtual ~ExtensionWindow();
virtual void MessageReceived(BMessage* message);
virtual bool QuitRequested();
private:
BMessenger fTarget;
BMimeType fMimeType;
BString fExtension;
BTextControl* fExtensionControl;
BButton* fAcceptButton;
};
#endif // EXTENSION_WINDOW_H

View File

@ -4,12 +4,11 @@
*/
#include "ApplicationTypesWindow.h"
#include "FileTypes.h"
#include "FileTypesWindow.h"
#include <Application.h>
//#include <Screen.h>
//#include <Autolock.h>
#include <Alert.h>
#include <TextView.h>
#include <FilePanel.h>
@ -39,21 +38,28 @@ class FileTypes : public BApplication {
virtual bool QuitRequested();
private:
void _WindowClosed();
BFilePanel *fFilePanel;
BWindow *fTypesWindow;
BWindow *fApplicationTypesWindow;
uint32 fWindowCount;
BRect fTypesWindowFrame;
BRect fApplicationTypesWindowFrame;
};
FileTypes::FileTypes()
: BApplication(kSignature),
fTypesWindow(NULL),
fApplicationTypesWindow(NULL),
fWindowCount(0)
{
fFilePanel = new BFilePanel(B_OPEN_PANEL, NULL, NULL,
B_FILE_NODE | B_DIRECTORY_NODE, false);
fTypesWindowFrame = BRect(80.0f, 80.0f, 600.0f, 480.0f);
fApplicationTypesWindowFrame = BRect(100.0f, 100.0f, 540.0f, 480.0f);
// TODO: read from settings
}
@ -141,6 +147,14 @@ FileTypes::ArgvReceived(int32 argc, char **argv)
}
void
FileTypes::_WindowClosed()
{
if (--fWindowCount == 0 && !fFilePanel->IsShowing())
PostMessage(B_QUIT_REQUESTED);
}
void
FileTypes::MessageReceived(BMessage *message)
{
@ -153,15 +167,30 @@ FileTypes::MessageReceived(BMessage *message)
} else
fTypesWindow->Activate(true);
break;
case kMsgTypesWindowClosed:
fTypesWindow = NULL;
// supposed to fall through
case kMsgWindowClosed:
if (--fWindowCount == 0 && !fFilePanel->IsShowing())
PostMessage(B_QUIT_REQUESTED);
_WindowClosed();
break;
case kMsgOpenApplicationTypesWindow:
if (fApplicationTypesWindow == NULL) {
fApplicationTypesWindow = new ApplicationTypesWindow(
fApplicationTypesWindowFrame);
fApplicationTypesWindow->Show();
fWindowCount++;
} else
fApplicationTypesWindow->Activate(true);
break;
case kMsgApplicationTypesWindowClosed:
fApplicationTypesWindow = NULL;
_WindowClosed();
break;
case kMsgWindowClosed:
_WindowClosed();
break;
case kMsgOpenFilePanel:
// the open file panel sends us a message when it's done
fFilePanel->Window()->SetTitle("FileTypes: Open File");

View File

@ -17,6 +17,10 @@ static const uint32 kMsgOpenSameAsPanel = 'opAp';
static const uint32 kMsgOpenTypesWindow = 'opTw';
static const uint32 kMsgTypesWindowClosed = 'clTw';
static const uint32 kMsgOpenApplicationTypesWindow = 'opAw';
static const uint32 kMsgApplicationTypesWindowClosed = 'clAw';
static const uint32 kMsgWindowClosed = 'WiCl';
#endif // FILE_TYPES_H

View File

@ -4,10 +4,12 @@
*/
#include "ExtensionWindow.h"
#include "FileTypes.h"
#include "FileTypesWindow.h"
#include "MimeTypeListView.h"
#include "NewFileTypeWindow.h"
#include "StringView.h"
#include <AppFileInfo.h>
#include <Application.h>
@ -498,9 +500,7 @@ AttributeListView::Draw(BRect updateRect)
FileTypesWindow::FileTypesWindow(BRect frame)
: BWindow(frame, "FileTypes", B_TITLED_WINDOW,
B_NOT_ZOOMABLE | B_ASYNCHRONOUS_CONTROLS),
fNewTypeWindow(NULL),
fExtensionWindow(NULL),
fAttributeWindow(NULL)
fNewTypeWindow(NULL)
{
// add the menu
@ -517,7 +517,7 @@ FileTypesWindow::FileTypesWindow(BRect frame)
item->SetShortcut('O', B_COMMAND_KEY);
menu->AddItem(item);
menu->AddItem(new BMenuItem("Application Types" B_UTF8_ELLIPSIS,
new BMessage));
new BMessage(kMsgOpenApplicationTypesWindow)));
menu->AddSeparatorItem();
menu->AddItem(new BMenuItem("About FileTypes" B_UTF8_ELLIPSIS,
@ -558,7 +558,7 @@ FileTypesWindow::FileTypesWindow(BRect frame)
if (rect.right < 180)
rect.right = 180;
fTypeListView = new MimeTypeListView(rect, "listview",
fTypeListView = new MimeTypeListView(rect, "listview", NULL, false, false,
B_FOLLOW_LEFT | B_FOLLOW_TOP_BOTTOM);
fTypeListView->SetSelectionMessage(new BMessage(kMsgTypeSelected));
@ -644,23 +644,24 @@ FileTypesWindow::FileTypesWindow(BRect frame)
innerRect = box->Bounds().InsetByCopy(8.0f, 6.0f);
innerRect.top += ceilf(fontHeight.ascent);
innerRect.bottom = innerRect.top + button->Bounds().Height();
fInternalNameControl = new BTextControl(innerRect, "internal", "Internal Name:", "",
NULL, B_FOLLOW_LEFT_RIGHT);
labelWidth = fInternalNameControl->StringWidth(fInternalNameControl->Label()) + 2.0f;
fInternalNameControl->SetDivider(labelWidth);
fInternalNameControl->SetAlignment(B_ALIGN_RIGHT, B_ALIGN_LEFT);
fInternalNameControl->SetEnabled(false);
box->ResizeBy(0, fInternalNameControl->Bounds().Height() * 3.0f);
box->AddChild(fInternalNameControl);
fInternalNameView = new StringView(innerRect, "internal", "Internal Name:", "",
B_FOLLOW_LEFT_RIGHT);
labelWidth = fInternalNameView->StringWidth(fInternalNameView->Label()) + 2.0f;
fInternalNameView->SetDivider(labelWidth);
fInternalNameView->SetEnabled(false);
fInternalNameView->ResizeToPreferred();
box->AddChild(fInternalNameView);
innerRect.OffsetBy(0, fInternalNameControl->Bounds().Height() + 5.0f);
innerRect.OffsetBy(0, fInternalNameView->Bounds().Height() + 5.0f);
fTypeNameControl = new BTextControl(innerRect, "type", "Type Name:", "",
new BMessage(kMsgTypeEntered), B_FOLLOW_LEFT_RIGHT);
fTypeNameControl->SetDivider(labelWidth);
fTypeNameControl->SetAlignment(B_ALIGN_RIGHT, B_ALIGN_LEFT);
box->ResizeBy(0, fInternalNameView->Bounds().Height()
+ fTypeNameControl->Bounds().Height() * 2.0f);
box->AddChild(fTypeNameControl);
innerRect.OffsetBy(0, fInternalNameControl->Bounds().Height() + 5.0f);
innerRect.OffsetBy(0, fTypeNameControl->Bounds().Height() + 5.0f);
fDescriptionControl = new BTextControl(innerRect, "description", "Description:", "",
new BMessage(kMsgDescriptionEntered), B_FOLLOW_LEFT_RIGHT);
fDescriptionControl->SetDivider(labelWidth);
@ -1060,7 +1061,7 @@ FileTypesWindow::_SetType(BMimeType* type, int32 forceUpdate)
if (&fCurrentType != type)
fCurrentType.SetTo(type->Type());
fInternalNameControl->SetText(type->Type());
fInternalNameView->SetText(type->Type());
char description[B_MIME_TYPE_LENGTH];
@ -1077,7 +1078,7 @@ FileTypesWindow::_SetType(BMimeType* type, int32 forceUpdate)
}
} else {
fCurrentType.Unset();
fInternalNameControl->SetText(NULL);
fInternalNameView->SetText(NULL);
fTypeNameControl->SetText(NULL);
fDescriptionControl->SetText(NULL);
}
@ -1098,6 +1099,7 @@ FileTypesWindow::_SetType(BMimeType* type, int32 forceUpdate)
fIconView->SetEnabled(enabled);
fInternalNameView->SetEnabled(enabled);
fTypeNameControl->SetEnabled(enabled);
fDescriptionControl->SetEnabled(enabled);
fPreferredField->SetEnabled(enabled);
@ -1205,12 +1207,31 @@ FileTypesWindow::MessageReceived(BMessage* message)
}
case kMsgExtensionInvoked:
puts("ext");
{
if (fCurrentType.Type() == NULL)
break;
int32 index;
if (message->FindInt32("index", &index) == B_OK) {
BStringItem* item = (BStringItem*)fExtensionListView->ItemAt(index);
if (item == NULL)
break;
BWindow* window = new ExtensionWindow(this, fCurrentType, item->Text());
window->Show();
}
break;
}
case kMsgAddExtension:
puts("add ext");
{
if (fCurrentType.Type() == NULL)
break;
BWindow* window = new ExtensionWindow(this, fCurrentType, NULL);
window->Show();
break;
}
case kMsgRemoveExtension:
{

View File

@ -20,6 +20,7 @@ class BTextControl;
class AttributeListView;
class IconView;
class MimeTypeListView;
class StringView;
class FileTypesWindow : public BWindow {
@ -53,7 +54,7 @@ class FileTypesWindow : public BWindow {
BButton* fAddExtensionButton;
BButton* fRemoveExtensionButton;
BTextControl* fInternalNameControl;
StringView* fInternalNameView;
BTextControl* fTypeNameControl;
BTextControl* fDescriptionControl;
@ -66,8 +67,6 @@ class FileTypesWindow : public BWindow {
BButton* fRemoveAttributeButton;
BWindow* fNewTypeWindow;
BWindow* fExtensionWindow;
BWindow* fAttributeWindow;
};
static const uint32 kMsgPreferredAppOpened = 'paOp';

View File

@ -8,8 +8,11 @@ SubDirSysHdrs $(HAIKU_TOP) src kits tracker ;
Preference FileTypes :
FileTypes.cpp
FileTypesWindow.cpp
ApplicationTypesWindow.cpp
MimeTypeListView.cpp
NewFileTypeWindow.cpp
ExtensionWindow.cpp
StringView.cpp
: be tracker
: FileTypes.rdef FileTypes.icons.rdef
;

View File

@ -6,7 +6,7 @@
#include "MimeTypeListView.h"
#include <Mime.h>
#include <Bitmap.h>
// TODO: lazy type collecting (super types only at startup)
@ -28,17 +28,21 @@ mimetype_is_application_signature(BMimeType& type)
// #pragma mark -
MimeTypeItem::MimeTypeItem(BMimeType& type, bool flat)
MimeTypeItem::MimeTypeItem(BMimeType& type, bool showIcon, bool flat)
: BStringItem(type.Type(), !flat && !type.IsSupertypeOnly() ? 1 : 0, false),
fType(type.Type())
fType(type.Type()),
fFlat(flat),
fShowIcon(showIcon)
{
_SetTo(type);
}
MimeTypeItem::MimeTypeItem(const char* type, bool flat)
MimeTypeItem::MimeTypeItem(const char* type, bool showIcon, bool flat)
: BStringItem(type, !flat && strchr(type, '/') != NULL ? 1 : 0, false),
fType(type)
fType(type),
fFlat(flat),
fShowIcon(showIcon)
{
BMimeType mimeType(type);
_SetTo(mimeType);
@ -51,7 +55,7 @@ MimeTypeItem::~MimeTypeItem()
void
MimeTypeItem::DrawItem(BView* owner, BRect itemRect, bool drawEverything)
MimeTypeItem::DrawItem(BView* owner, BRect frame, bool complete)
{
BFont font;
@ -62,13 +66,70 @@ MimeTypeItem::DrawItem(BView* owner, BRect itemRect, bool drawEverything)
owner->SetFont(&boldFont);
}
BStringItem::DrawItem(owner, itemRect, drawEverything);
BRect rect = frame;
if (fFlat) {
// This is where the latch would be - yet can freely consider this
// as an ugly hack
rect.left -= 11.0f;
}
if (fShowIcon) {
rgb_color highColor = owner->HighColor();
rgb_color lowColor = owner->LowColor();
if (IsSelected() || complete) {
if (IsSelected())
owner->SetLowColor(tint_color(lowColor, B_DARKEN_2_TINT));
owner->FillRect(rect, B_SOLID_LOW);
}
BBitmap bitmap(BRect(0, 0, B_MINI_ICON - 1, B_MINI_ICON - 1), B_CMAP8);
BMimeType mimeType(fType.String());
if (mimeType.GetIcon(&bitmap, B_MINI_ICON) == B_OK) {
BPoint point(rect.left + 2.0f,
rect.top + (rect.Height() - B_MINI_ICON) / 2.0f);
owner->SetDrawingMode(B_OP_ALPHA);
owner->DrawBitmap(&bitmap, point);
}
owner->SetDrawingMode(B_OP_COPY);
owner->MovePenTo(rect.left + B_MINI_ICON + 8.0f, frame.top + fBaselineOffset);
owner->SetHighColor(0, 0, 0);
owner->DrawString(Text());
owner->SetHighColor(highColor);
owner->SetLowColor(lowColor);
} else
BStringItem::DrawItem(owner, rect, complete);
if (IsSupertypeOnly())
owner->SetFont(&font);
}
void
MimeTypeItem::Update(BView* owner, const BFont* font)
{
BStringItem::Update(owner, font);
if (fShowIcon) {
SetWidth(Width() + B_MINI_ICON + 2.0f);
if (Height() < B_MINI_ICON + 4.0f)
SetHeight(B_MINI_ICON + 4.0f);
font_height fontHeight;
font->GetHeight(&fontHeight);
fBaselineOffset = fontHeight.ascent
+ (Height() - ceilf(fontHeight.ascent + fontHeight.descent)) / 2.0f;
}
}
void
MimeTypeItem::_SetTo(BMimeType& type)
{
@ -86,12 +147,12 @@ MimeTypeItem::_SetTo(BMimeType& type)
fSubtype.SetTo(subType + 1);
// omit the slash
Update();
UpdateText();
}
void
MimeTypeItem::Update()
MimeTypeItem::UpdateText()
{
if (IsSupertypeOnly())
return;
@ -171,19 +232,43 @@ MimeTypeItem::CompareLabels(const BListItem* a, const BListItem* b)
MimeTypeListView::MimeTypeListView(BRect rect, const char* name,
const char* supertype, bool showIcons, bool applicationMode,
uint32 resizingMode)
: BOutlineListView(rect, name, B_SINGLE_SELECTION_LIST, resizingMode)
: BOutlineListView(rect, name, B_SINGLE_SELECTION_LIST, resizingMode),
fSupertype(supertype),
fShowIcons(showIcons),
fApplicationMode(applicationMode)
{
_CollectTypes();
}
MimeTypeListView::~MimeTypeListView()
{
// free items, stupid BOutlineListView doesn't do this itself
}
for (int32 i = FullListCountItems(); i-- > 0;) {
delete FullListItemAt(i);
void
MimeTypeListView::_CollectSubtypes(const char* supertype, MimeTypeItem* supertypeItem)
{
BMessage types;
if (BMimeType::GetInstalledTypes(supertype, &types) != B_OK)
return;
const char* type;
int32 index = 0;
while (types.FindString("types", index++, &type) == B_OK) {
BMimeType mimeType(type);
bool isApp = mimetype_is_application_signature(mimeType);
if (fApplicationMode ^ isApp)
continue;
BStringItem* typeItem = new MimeTypeItem(mimeType, fShowIcons,
supertypeItem == NULL);
if (supertypeItem != NULL)
AddUnder(typeItem, supertypeItem);
else
AddItem(typeItem);
}
}
@ -191,30 +276,21 @@ MimeTypeListView::~MimeTypeListView()
void
MimeTypeListView::_CollectTypes()
{
BMessage superTypes;
if (BMimeType::GetInstalledSupertypes(&superTypes) != B_OK)
return;
if (fSupertype.Type() != NULL) {
// only show MIME types that belong to this supertype
_CollectSubtypes(fSupertype.Type(), NULL);
} else {
BMessage superTypes;
if (BMimeType::GetInstalledSupertypes(&superTypes) != B_OK)
return;
const char* superType;
int32 index = 0;
while (superTypes.FindString("super_types", index++, &superType) == B_OK) {
BStringItem* superTypeItem = new MimeTypeItem(superType);
AddItem(superTypeItem);
const char* supertype;
int32 index = 0;
while (superTypes.FindString("super_types", index++, &supertype) == B_OK) {
MimeTypeItem* supertypeItem = new MimeTypeItem(supertype);
AddItem(supertypeItem);
BMessage types;
if (BMimeType::GetInstalledTypes(superType, &types) != B_OK)
continue;
const char* type;
int32 typeIndex = 0;
while (types.FindString("types", typeIndex++, &type) == B_OK) {
BMimeType mimeType(type);
if (mimetype_is_application_signature(mimeType))
continue;
BStringItem* typeItem = new MimeTypeItem(mimeType);
AddUnder(typeItem, superTypeItem);
_CollectSubtypes(supertype, supertypeItem);
}
}
@ -225,7 +301,10 @@ MimeTypeListView::_CollectTypes()
void
MimeTypeListView::_MakeTypesUnique(MimeTypeItem* underItem)
{
SortItemsUnder(underItem, underItem != NULL, &MimeTypeItem::Compare);
#ifndef __HAIKU__
if (fSupertype.Type() == NULL)
#endif
SortItemsUnder(underItem, underItem != NULL, &MimeTypeItem::Compare);
bool lastItemSame = false;
MimeTypeItem* last = NULL;
@ -282,6 +361,7 @@ MimeTypeListView::AttachedToWindow()
BOutlineListView::AttachedToWindow();
BMimeType::StartWatching(this);
_CollectTypes();
}
@ -289,8 +369,13 @@ void
MimeTypeListView::DetachedFromWindow()
{
BOutlineListView::DetachedFromWindow();
BMimeType::StopWatching(this);
// free all items, they will be retrieved again in AttachedToWindow()
for (int32 i = FullListCountItems(); i-- > 0;) {
delete FullListItemAt(i);
}
}
@ -442,7 +527,7 @@ MimeTypeListView::UpdateItem(MimeTypeItem* item)
if (IndexOf(item) == CurrentSelection())
selected = CurrentSelection();
item->Update();
item->UpdateText();
_MakeTypesUnique(dynamic_cast<MimeTypeItem*>(Superitem(item)));
if (selected != -1) {

View File

@ -6,20 +6,20 @@
#define MIME_TYPE_LIST_VIEW_H
#include <Mime.h>
#include <OutlineListView.h>
#include <String.h>
class BMimeType;
class MimeTypeItem : public BStringItem {
public:
MimeTypeItem(BMimeType& type, bool flat = false);
MimeTypeItem(const char* type, bool flat = false);
MimeTypeItem(BMimeType& type, bool showIcon = false, bool flat = false);
MimeTypeItem(const char* type, bool showIcon = false, bool flat = false);
virtual ~MimeTypeItem();
virtual void DrawItem(BView* owner, BRect itemRect,
bool drawEverything = false);
virtual void Update(BView* owner, const BFont* font);
const char* Type() const { return fType.String(); }
const char* Subtype() const { return fSubtype.String(); }
@ -27,7 +27,7 @@ class MimeTypeItem : public BStringItem {
const char* Description() const { return fDescription.String(); }
bool IsSupertypeOnly() const { return fIsSupertype; }
void Update();
void UpdateText();
void AddSubtype();
static int Compare(const BListItem* a, const BListItem* b);
@ -40,12 +40,17 @@ class MimeTypeItem : public BStringItem {
BString fSubtype;
BString fType;
BString fDescription;
float fBaselineOffset;
bool fIsSupertype;
bool fFlat;
bool fShowIcon;
};
class MimeTypeListView : public BOutlineListView {
public:
MimeTypeListView(BRect rect, const char* name,
const char* supertype = NULL, bool showIcons = false,
bool applicationMode = false,
uint32 resizingMode = B_FOLLOW_LEFT | B_FOLLOW_TOP);
virtual ~MimeTypeListView();
@ -64,10 +69,14 @@ class MimeTypeListView : public BOutlineListView {
virtual void MessageReceived(BMessage* message);
private:
void _CollectSubtypes(const char* supertype, MimeTypeItem* supertypeItem);
void _CollectTypes();
void _MakeTypesUnique(MimeTypeItem* underItem = NULL);
BString fSelectNewType;
BMimeType fSupertype;
BString fSelectNewType;
bool fShowIcons;
bool fApplicationMode;
};
bool mimetype_is_application_signature(BMimeType& type);

View File

@ -121,7 +121,7 @@ NewFileTypeWindow::~NewFileTypeWindow()
{
}
#include <stdio.h>
void
NewFileTypeWindow::MessageReceived(BMessage* message)
{

View File

@ -13,6 +13,8 @@ class BButton;
class BMenu;
class BTextControl;
class FileTypesWindow;
class NewFileTypeWindow : public BWindow {
public:

View File

@ -0,0 +1,218 @@
/*
* Copyright 2006, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
* Distributed under the terms of the MIT License.
*/
#include "StringView.h"
//#include <Region.h>
StringView::StringView(BRect frame, const char* name, const char* label,
const char* text, uint32 resizeMask, uint32 flags)
: BView(frame, name, resizeMask, flags),
fLabel(label),
fText(text),
fLabelAlignment(B_ALIGN_RIGHT),
fTextAlignment(B_ALIGN_LEFT)
{
fDivider = StringWidth(label) + 4.0f;
}
StringView::~StringView()
{
}
void
StringView::SetAlignment(alignment labelAlignment, alignment textAlignment)
{
if (labelAlignment == fLabelAlignment && textAlignment == fTextAlignment)
return;
fLabelAlignment = labelAlignment;
fTextAlignment = textAlignment;
Invalidate();
}
void
StringView::GetAlignment(alignment* _label, alignment* _text) const
{
if (_label)
*_label = fLabelAlignment;
if (_text)
*_text = fTextAlignment;
}
void
StringView::SetDivider(float divider)
{
fDivider = divider;
_UpdateText();
Invalidate();
}
void
StringView::AttachedToWindow()
{
if (Parent() != NULL)
SetViewColor(Parent()->ViewColor());
else
SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
SetLowColor(ViewColor());
_UpdateText();
}
void
StringView::Draw(BRect updateRect)
{
BRect rect = Bounds();
font_height fontHeight;
GetFontHeight(&fontHeight);
float y = ceilf(fontHeight.ascent) + 1.0f;
float x;
SetHighColor(IsEnabled() ? ui_color(B_CONTROL_TEXT_COLOR)
: tint_color(ui_color(B_PANEL_BACKGROUND_COLOR), B_DISABLED_LABEL_TINT));
if (Label()) {
switch (fLabelAlignment) {
case B_ALIGN_RIGHT:
x = Divider() - StringWidth(Label()) - 3.0f;
break;
case B_ALIGN_CENTER:
x = Divider() - StringWidth(Label()) / 2.0f;
break;
default:
x = 1.0f;
break;
}
DrawString(Label(), BPoint(x, y));
}
if (fTruncatedText.String() != NULL) {
switch (fTextAlignment) {
case B_ALIGN_RIGHT:
x = rect.Width() - StringWidth(fTruncatedText.String());
break;
case B_ALIGN_CENTER:
x = Divider() + (rect.Width() - Divider() - StringWidth(Label())) / 2.0f;
break;
default:
x = Divider() + 3.0f;
break;
}
DrawString(fTruncatedText.String(), BPoint(x, y));
}
}
void
StringView::FrameResized(float width, float height)
{
BString oldTruncated = fTruncatedText;
_UpdateText();
if (oldTruncated != fTruncatedText) {
// invalidate text portion only
BRect rect = Bounds();
rect.left = Divider();
Invalidate(rect);
}
}
void
StringView::ResizeToPreferred()
{
float width, height;
GetPreferredSize(&width, &height);
// Resize the width only for B_ALIGN_LEFT (if its large enough already, that is)
if (Bounds().Width() > width
&& (fLabelAlignment != B_ALIGN_LEFT || fTextAlignment != B_ALIGN_LEFT))
width = Bounds().Width();
BView::ResizeTo(width, height);
}
void
StringView::GetPreferredSize(float* _width, float* _height)
{
if (!Text() && !Label()) {
BView::GetPreferredSize(_width, _height);
return;
}
if (_width)
*_width = 7.0f + ceilf(StringWidth(Label()) + StringWidth(Text()));
if (_height) {
font_height fontHeight;
GetFontHeight(&fontHeight);
*_height = ceil(fontHeight.ascent + fontHeight.descent + fontHeight.leading) + 2.0f;
}
}
void
StringView::SetEnabled(bool enabled)
{
if (IsEnabled() == enabled)
return;
fEnabled = enabled;
Invalidate();
}
void
StringView::SetLabel(const char* label)
{
fLabel = label;
// invalidate label portion only
BRect rect = Bounds();
rect.right = Divider();
Invalidate(rect);
}
void
StringView::SetText(const char* text)
{
fText = text;
_UpdateText();
// invalidate text portion only
BRect rect = Bounds();
rect.left = Divider();
Invalidate(rect);
}
void
StringView::_UpdateText()
{
fTruncatedText = fText;
TruncateString(&fTruncatedText, B_TRUNCATE_MIDDLE, Bounds().Width() - Divider());
}

View File

@ -0,0 +1,55 @@
/*
* Copyright 2006, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
* Distributed under the terms of the MIT License.
*/
#ifndef STRING_VIEW_H
#define STRING_VIEW_H
#include <String.h>
#include <View.h>
class StringView : public BView {
public:
StringView(BRect frame, const char* name, const char* label,
const char* text, uint32 resizeMask = B_FOLLOW_LEFT | B_FOLLOW_TOP,
uint32 flags = B_WILL_DRAW | B_FRAME_EVENTS);
virtual ~StringView();
virtual void Draw(BRect updateRect);
virtual void AttachedToWindow();
virtual void FrameResized(float width, float height);
virtual void GetPreferredSize(float* _width, float* _height);
virtual void ResizeToPreferred();
void SetEnabled(bool enabled);
bool IsEnabled() const { return fEnabled; }
void SetLabel(const char* label);
const char* Label() const { return fLabel.String(); }
void SetText(const char* text);
const char* Text() const { return fText.String(); }
void SetDivider(float divider);
float Divider() const { return fDivider; }
void SetAlignment(alignment labelAlignment, alignment textAlignment);
void GetAlignment(alignment* _label, alignment* _text) const;
private:
void _UpdateText();
BString fLabel;
BString fText;
BString fTruncatedText;
float fDivider;
alignment fLabelAlignment;
alignment fTextAlignment;
bool fEnabled;
};
#endif // STRING_VIEW_H