#include "ProbeView.h"
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <Alert.h>
#include <Application.h>
#include <Autolock.h>
#include <Beep.h>
#include <Bitmap.h>
#include <Box.h>
#include <Button.h>
#include <Catalog.h>
#include <ControlLook.h>
#include <Clipboard.h>
#include <Directory.h>
#include <Entry.h>
#include <ExpressionParser.h>
#include <fs_attr.h>
#include <GridView.h>
#include <GroupLayout.h>
#include <GroupLayoutBuilder.h>
#include <GroupView.h>
#include <LayoutBuilder.h>
#include <Locale.h>
#include <MenuBar.h>
#include <MenuItem.h>
#include <MessageQueue.h>
#include <NodeInfo.h>
#include <Node.h>
#include <NodeMonitor.h>
#include <Path.h>
#include <PrintJob.h>
#include <ScrollView.h>
#include <StringView.h>
#include <Slider.h>
#include <String.h>
#include <TextControl.h>
#include <Volume.h>
#include <Window.h>
#include "DataView.h"
#include "DiskProbe.h"
#include "TypeEditors.h"
#undef B_TRANSLATION_CONTEXT
#define B_TRANSLATION_CONTEXT "ProbeView"
static const uint32 kMsgSliderUpdate = 'slup';
static const uint32 kMsgPositionUpdate = 'poup';
static const uint32 kMsgLastPosition = 'lpos';
static const uint32 kMsgFontSize = 'fnts';
static const uint32 kMsgBlockSize = 'blks';
static const uint32 kMsgAddBookmark = 'bmrk';
static const uint32 kMsgPrint = 'prnt';
static const uint32 kMsgPageSetup = 'pgsp';
static const uint32 kMsgViewAs = 'vwas';
static const uint32 kMsgStopFind = 'sfnd';
class IconView : public BView {
public:
IconView(const entry_ref* ref, bool isDevice);
virtual ~IconView();
virtual void AttachedToWindow();
virtual void Draw(BRect updateRect);
void UpdateIcon();
private:
entry_ref fRef;
bool fIsDevice;
BBitmap* fBitmap;
};
class PositionSlider : public BSlider {
public:
PositionSlider(const char* name,
BMessage* message, off_t size,
uint32 blockSize);
virtual ~PositionSlider();
off_t Position() const;
off_t Size() const { return fSize; }
uint32 BlockSize() const { return fBlockSize; }
virtual void SetPosition(float position);
void SetPosition(off_t position);
void SetSize(off_t size);
void SetBlockSize(uint32 blockSize);
private:
void Reset();
private:
static const int32 kMaxSliderLimit = 0x7fffff80;
off_t fSize;
uint32 fBlockSize;
};
class HeaderView : public BGridView, public BInvoker {
public:
HeaderView(const entry_ref* ref,
DataEditor& editor);
virtual ~HeaderView();
virtual void AttachedToWindow();
virtual void DetachedFromWindow();
virtual void MessageReceived(BMessage* message);
base_type Base() const { return fBase; }
void SetBase(base_type);
off_t CursorOffset() const
{ return fPosition % fBlockSize; }
off_t Position() const { return fPosition; }
uint32 BlockSize() const { return fBlockSize; }
void SetTo(off_t position, uint32 blockSize);
void UpdateIcon();
private:
void FormatValue(char* buffer, size_t bufferSize,
off_t value);
void UpdatePositionViews(bool all = true);
void UpdateOffsetViews(bool all = true);
void UpdateFileSizeView();
void NotifyTarget();
private:
const char* fAttribute;
off_t fFileSize;
uint32 fBlockSize;
base_type fBase;
off_t fPosition;
off_t fLastPosition;
BTextControl* fTypeControl;
BTextControl* fPositionControl;
BStringView* fPathView;
BStringView* fSizeView;
BTextControl* fOffsetControl;
BTextControl* fFileOffsetControl;
PositionSlider* fPositionSlider;
IconView* fIconView;
BButton* fStopButton;
};
class TypeMenuItem : public BMenuItem {
public:
TypeMenuItem(const char* name, const char* type,
BMessage* message);
virtual void GetContentSize(float* _width, float* _height);
virtual void DrawContent();
private:
BString fType;
};
class EditorLooper : public BLooper {
public:
EditorLooper(const char* name,
DataEditor& editor, BMessenger messenger);
virtual ~EditorLooper();
virtual void MessageReceived(BMessage* message);
bool FindIsRunning() const { return !fQuitFind; }
void Find(off_t startAt, const uint8* data,
size_t dataSize, bool caseInsensitive,
BMessenger progressMonitor);
void QuitFind();
private:
DataEditor& fEditor;
BMessenger fMessenger;
volatile bool fQuitFind;
};
class TypeView : public BView {
public:
TypeView(const char* name, int32 index, DataEditor& editor);
virtual ~TypeView();
private:
BView* fTypeEditorView;
};
static void
get_type_string(char* buffer, size_t bufferSize, type_code type)
{
for (int32 i = 0; i < 4; i++) {
buffer[i] = type >> (24 - 8 * i);
if (buffer[i] < ' ' || buffer[i] == 0x7f) {
snprintf(buffer, bufferSize, "0x%04" B_PRIx32, type);
break;
} else if (i == 3)
buffer[4] = '\0';
}
}
IconView::IconView(const entry_ref* ref, bool isDevice)
: BView(NULL, B_WILL_DRAW),
fRef(*ref),
fIsDevice(isDevice),
fBitmap(NULL)
{
UpdateIcon();
if (fBitmap != NULL)
SetExplicitSize(fBitmap->Bounds().Size());
}
IconView::~IconView()
{
delete fBitmap;
}
void
IconView::AttachedToWindow()
{
SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
}
void
IconView::Draw(BRect updateRect)
{
if (fBitmap == NULL)
return;
SetDrawingMode(B_OP_ALPHA);
DrawBitmap(fBitmap, updateRect, updateRect);
SetDrawingMode(B_OP_COPY);
}
void
IconView::UpdateIcon()
{
if (fBitmap == NULL) {
fBitmap = new BBitmap(BRect(BPoint(0, 0), be_control_look->ComposeIconSize(B_LARGE_ICON)),
B_RGBA32);
}
if (fBitmap != NULL) {
status_t status = B_ERROR;
if (fIsDevice) {
BPath path(&fRef);
status = get_device_icon(path.Path(), fBitmap, B_LARGE_ICON);
} else {
status = BNodeInfo::GetTrackerIcon(&fRef, fBitmap,
(icon_size)(fBitmap->Bounds().IntegerWidth() + 1));
}
if (status != B_OK) {
BMimeType type(B_FILE_MIME_TYPE);
status = type.GetIcon(fBitmap, B_LARGE_ICON);
}
if (status != B_OK) {
delete fBitmap;
fBitmap = NULL;
}
Invalidate();
}
}
PositionSlider::PositionSlider(const char* name, BMessage* message,
off_t size, uint32 blockSize)
:
BSlider(name, NULL, message, 0, kMaxSliderLimit, B_HORIZONTAL,
B_TRIANGLE_THUMB),
fSize(size),
fBlockSize(blockSize)
{
Reset();
rgb_color color = ui_color(B_CONTROL_HIGHLIGHT_COLOR);
UseFillColor(true, &color);
}
PositionSlider::~PositionSlider()
{
}
void
PositionSlider::Reset()
{
SetKeyIncrementValue(int32(1.0 * kMaxSliderLimit / ((fSize - 1) / fBlockSize) + 0.5));
SetEnabled(fSize > fBlockSize);
}
off_t
PositionSlider::Position() const
{
return (off_t(1.0 * (fSize - 1) * Value() / kMaxSliderLimit + 0.5) / fBlockSize) * fBlockSize;
}
void
PositionSlider::SetPosition(float position)
{
BSlider::SetPosition(position);
}
void
PositionSlider::SetPosition(off_t position)
{
position /= fBlockSize;
SetValue(int32(1.0 * kMaxSliderLimit * position / ((fSize - 1) / fBlockSize) + 0.5));
}
void
PositionSlider::SetSize(off_t size)
{
if (size == fSize)
return;
off_t position = Position();
if (position >= size)
position = size - 1;
fSize = size;
Reset();
SetPosition(position);
}
void
PositionSlider::SetBlockSize(uint32 blockSize)
{
if (blockSize == fBlockSize)
return;
off_t position = Position();
fBlockSize = blockSize;
Reset();
SetPosition(position);
}
HeaderView::HeaderView(const entry_ref* ref, DataEditor& editor)
: BGridView("probeHeader", B_USE_SMALL_SPACING, B_USE_SMALL_SPACING),
fAttribute(editor.Attribute()),
fFileSize(editor.FileSize()),
fBlockSize(editor.BlockSize()),
fBase(kHexBase),
fPosition(0),
fLastPosition(0)
{
SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
GridLayout()->SetInsets(B_USE_WINDOW_SPACING, B_USE_WINDOW_SPACING,
B_USE_WINDOW_SPACING, B_USE_DEFAULT_SPACING);
fIconView = new IconView(ref, editor.IsDevice());
GridLayout()->AddView(fIconView, 0, 0, 1, 2);
BGroupView* line = new BGroupView(B_HORIZONTAL);
GridLayout()->AddView(line, 1, 0);
BFont boldFont = *be_bold_font;
BFont plainFont = *be_plain_font;
boldFont.SetSize(ceilf(plainFont.Size() * 0.83));
plainFont.SetSize(ceilf(plainFont.Size() * 0.83));
BStringView* stringView = new BStringView(
B_EMPTY_STRING, editor.IsAttribute()
? B_TRANSLATE("Attribute: ") : editor.IsDevice()
? B_TRANSLATE("Device: ") : B_TRANSLATE("File: "));
stringView->SetFont(&boldFont);
line->AddChild(stringView);
BPath path(ref);
BString string = path.Path();
if (fAttribute != NULL) {
string.Prepend(" (");
string.Prepend(fAttribute);
string.Append(")");
}
fPathView = new BStringView(B_EMPTY_STRING, string.String());
fPathView->SetFont(&plainFont);
line->AddChild(fPathView);
if (editor.IsAttribute()) {
stringView = new BStringView(B_EMPTY_STRING,
B_TRANSLATE("Attribute type: "));
stringView->SetFont(&boldFont);
line->AddChild(stringView);
char buffer[16];
get_type_string(buffer, sizeof(buffer), editor.Type());
fTypeControl = new BTextControl(B_EMPTY_STRING, NULL, buffer,
new BMessage(kMsgPositionUpdate));
fTypeControl->SetFont(&plainFont);
fTypeControl->TextView()->SetFontAndColor(&plainFont);
fTypeControl->SetEnabled(false);
line->AddChild(fTypeControl);
} else
fTypeControl = NULL;
fStopButton = new BButton(B_EMPTY_STRING,
B_TRANSLATE("Stop"), new BMessage(kMsgStopFind));
fStopButton->SetFont(&plainFont);
fStopButton->Hide();
line->AddChild(fStopButton);
BGroupLayoutBuilder(line).AddGlue();
line = new BGroupView(B_HORIZONTAL, B_USE_SMALL_SPACING);
GridLayout()->AddView(line, 1, 1);
stringView = new BStringView(B_EMPTY_STRING, B_TRANSLATE("Block: "));
stringView->SetFont(&boldFont);
line->AddChild(stringView);
BMessage* msg = new BMessage(kMsgPositionUpdate);
msg->AddBool("fPositionControl", true);
fPositionControl = new BTextControl(B_EMPTY_STRING, NULL, "0x0", msg);
fPositionControl->SetDivider(0.0);
fPositionControl->SetFont(&plainFont);
fPositionControl->TextView()->SetFontAndColor(&plainFont);
fPositionControl->SetAlignment(B_ALIGN_LEFT, B_ALIGN_LEFT);
line->AddChild(fPositionControl);
fSizeView = new BStringView(B_EMPTY_STRING, B_TRANSLATE_COMMENT("of "
"0x0", "This is a part of 'Block 0xXXXX of 0x0026' message. In "
"languages without 'of' structure it can be replaced simply "
"with '/'."));
fSizeView->SetFont(&plainFont);
line->AddChild(fSizeView);
UpdateFileSizeView();
stringView = new BStringView(B_EMPTY_STRING, B_TRANSLATE("Offset: "));
stringView->SetFont(&boldFont);
line->AddChild(stringView);
msg = new BMessage(kMsgPositionUpdate);
msg->AddBool("fOffsetControl", false);
fOffsetControl = new BTextControl(B_EMPTY_STRING, NULL, "0x0", msg);
fOffsetControl->SetDivider(0.0);
fOffsetControl->SetFont(&plainFont);
fOffsetControl->TextView()->SetFontAndColor(&plainFont);
fOffsetControl->SetAlignment(B_ALIGN_LEFT, B_ALIGN_LEFT);
line->AddChild(fOffsetControl);
UpdateOffsetViews(false);
stringView = new BStringView(B_EMPTY_STRING, editor.IsAttribute()
? B_TRANSLATE("Attribute offset: ") : editor.IsDevice()
? B_TRANSLATE("Device offset: ") : B_TRANSLATE("File offset: "));
stringView->SetFont(&boldFont);
line->AddChild(stringView);
msg = new BMessage(kMsgPositionUpdate);
msg->AddBool("fFileOffsetControl", false);
fFileOffsetControl = new BTextControl(B_EMPTY_STRING, NULL, "0x0", msg);
fFileOffsetControl->SetDivider(0.0);
fFileOffsetControl->SetFont(&plainFont);
fFileOffsetControl->TextView()->SetFontAndColor(&plainFont);
fFileOffsetControl->SetAlignment(B_ALIGN_LEFT, B_ALIGN_LEFT);
line->AddChild(fFileOffsetControl);
BGroupLayoutBuilder(line).AddGlue();
fPositionSlider = new PositionSlider("slider",
new BMessage(kMsgSliderUpdate), editor.FileSize(), editor.BlockSize());
fPositionSlider->SetModificationMessage(new BMessage(kMsgSliderUpdate));
fPositionSlider->SetBarThickness(8);
GridLayout()->AddView(fPositionSlider, 0, 2, 2, 1);
}
HeaderView::~HeaderView()
{
}
void
HeaderView::AttachedToWindow()
{
SetTarget(Window());
fStopButton->SetTarget(Parent());
fPositionControl->SetTarget(this);
fOffsetControl->SetTarget(this);
fFileOffsetControl->SetTarget(this);
fPositionSlider->SetTarget(this);
BMessage* message;
Window()->AddShortcut(B_HOME, B_COMMAND_KEY,
message = new BMessage(kMsgPositionUpdate), this);
message->AddInt64("block", 0);
Window()->AddShortcut(B_END, B_COMMAND_KEY,
message = new BMessage(kMsgPositionUpdate), this);
message->AddInt64("block", -1);
Window()->AddShortcut(B_PAGE_UP, B_COMMAND_KEY,
message = new BMessage(kMsgPositionUpdate), this);
message->AddInt32("delta", -1);
Window()->AddShortcut(B_PAGE_DOWN, B_COMMAND_KEY,
message = new BMessage(kMsgPositionUpdate), this);
message->AddInt32("delta", 1);
}
void
HeaderView::DetachedFromWindow()
{
Window()->RemoveShortcut(B_HOME, B_COMMAND_KEY);
Window()->RemoveShortcut(B_END, B_COMMAND_KEY);
Window()->RemoveShortcut(B_PAGE_UP, B_COMMAND_KEY);
Window()->RemoveShortcut(B_PAGE_DOWN, B_COMMAND_KEY);
}
void
HeaderView::UpdateIcon()
{
fIconView->UpdateIcon();
}
void
HeaderView::FormatValue(char* buffer, size_t bufferSize, off_t value)
{
snprintf(buffer, bufferSize, fBase == kHexBase ? "0x%" B_PRIxOFF : "%"
B_PRIdOFF, value);
}
void
HeaderView::UpdatePositionViews(bool all)
{
char buffer[64];
FormatValue(buffer, sizeof(buffer), fPosition / fBlockSize);
fPositionControl->SetText(buffer);
if (all) {
FormatValue(buffer, sizeof(buffer), fPosition);
fFileOffsetControl->SetText(buffer);
}
}
void
HeaderView::UpdateOffsetViews(bool all)
{
char buffer[64];
FormatValue(buffer, sizeof(buffer), fPosition % fBlockSize);
fOffsetControl->SetText(buffer);
if (all) {
FormatValue(buffer, sizeof(buffer), fPosition);
fFileOffsetControl->SetText(buffer);
}
}
void
HeaderView::UpdateFileSizeView()
{
BString string(B_TRANSLATE("of "));
char buffer[64];
FormatValue(buffer, sizeof(buffer),
(fFileSize + fBlockSize - 1) / fBlockSize);
string << buffer;
fSizeView->SetText(string.String());
}
void
HeaderView::SetBase(base_type type)
{
if (fBase == type)
return;
fBase = type;
UpdatePositionViews();
UpdateOffsetViews(false);
UpdateFileSizeView();
}
void
HeaderView::SetTo(off_t position, uint32 blockSize)
{
fPosition = position;
fLastPosition = (fLastPosition / fBlockSize) * blockSize;
fBlockSize = blockSize;
fPositionSlider->SetBlockSize(blockSize);
UpdatePositionViews();
UpdateOffsetViews(false);
UpdateFileSizeView();
}
void
HeaderView::NotifyTarget()
{
BMessage update(kMsgPositionUpdate);
update.AddInt64("position", fPosition);
Messenger().SendMessage(&update);
}
void
HeaderView::MessageReceived(BMessage* message)
{
switch (message->what) {
case B_OBSERVER_NOTICE_CHANGE: {
int32 what;
if (message->FindInt32(B_OBSERVE_WHAT_CHANGE, &what) != B_OK)
break;
switch (what) {
case kDataViewCursorPosition:
off_t offset;
if (message->FindInt64("position", &offset) == B_OK) {
fPosition = (fPosition / fBlockSize) * fBlockSize
+ offset;
UpdateOffsetViews();
}
break;
}
break;
}
case kMsgSliderUpdate:
{
if (Looper()->MessageQueue()->FindMessage(kMsgSliderUpdate, 0)
!= NULL)
break;
if (fPosition == fPositionSlider->Position())
break;
fLastPosition = fPosition;
fPosition = fPositionSlider->Position();
UpdatePositionViews();
NotifyTarget();
break;
}
case kMsgDataEditorFindProgress:
{
bool state;
if (message->FindBool("running", &state) == B_OK
&& fFileSize > fBlockSize) {
fPositionSlider->SetEnabled(!state);
if (state) {
fStopButton->Show();
} else {
fStopButton->Hide();
}
}
off_t position;
if (message->FindInt64("position", &position) != B_OK)
break;
fPosition = (position / fBlockSize) * fBlockSize;
UpdatePositionViews(false);
fPositionSlider->SetPosition(fPosition);
break;
}
case kMsgPositionUpdate:
{
off_t lastPosition = fPosition;
off_t position;
int32 delta;
bool round = true;
if (message->FindInt64("position", &position) == B_OK)
fPosition = position;
else if (message->FindInt64("block", &position) == B_OK) {
if (position < 0)
position += (fFileSize - 1) / fBlockSize + 1;
fPosition = position * fBlockSize;
} else if (message->FindInt32("delta", &delta) == B_OK) {
fPosition += delta * off_t(fBlockSize);
} else {
try {
ExpressionParser parser;
parser.SetSupportHexInput(true);
if (message->FindBool("fPositionControl", &round)
== B_OK) {
fPosition = parser.EvaluateToInt64(
fPositionControl->Text()) * fBlockSize;
} else if (message->FindBool("fOffsetControl", &round)
== B_OK) {
fPosition = (fPosition / fBlockSize) * fBlockSize +
parser.EvaluateToInt64(fOffsetControl->Text());
} else if (message->FindBool("fFileOffsetControl", &round)
== B_OK) {
fPosition = parser.EvaluateToInt64(
fFileOffsetControl->Text());
}
} catch (...) {
beep();
break;
}
}
fLastPosition = lastPosition;
if (round)
fPosition = (fPosition / fBlockSize) * fBlockSize;
if (fPosition < 0)
fPosition = 0;
else if (fPosition > ((fFileSize - 1) / fBlockSize) * fBlockSize)
fPosition = ((fFileSize - 1) / fBlockSize) * fBlockSize;
UpdatePositionViews();
fPositionSlider->SetPosition(fPosition);
NotifyTarget();
break;
}
case kMsgLastPosition:
{
fPosition = fLastPosition;
fLastPosition = fPositionSlider->Position();
UpdatePositionViews();
fPositionSlider->SetPosition(fPosition);
NotifyTarget();
break;
}
case kMsgBaseType:
{
int32 type;
if (message->FindInt32("base", &type) != B_OK)
break;
SetBase((base_type)type);
break;
}
default:
BView::MessageReceived(message);
}
}
TypeMenuItem::TypeMenuItem(const char* name, const char* type,
BMessage* message)
:
BMenuItem(name, message),
fType(type)
{
}
void
TypeMenuItem::GetContentSize(float* _width, float* _height)
{
BMenuItem::GetContentSize(_width, _height);
if (_width)
*_width += Menu()->StringWidth(fType.String());
}
void
TypeMenuItem::DrawContent()
{
BMenuItem::DrawContent();
font_height fontHeight;
Menu()->GetFontHeight(&fontHeight);
BPoint point = ContentLocation();
point.x = Frame().right - 4 - Menu()->StringWidth(fType.String());
point.y += fontHeight.ascent;
Menu()->DrawString(fType.String(), point);
}
EditorLooper::EditorLooper(const char* name, DataEditor& editor,
BMessenger target)
: BLooper(name),
fEditor(editor),
fMessenger(target),
fQuitFind(true)
{
fEditor.StartWatching(this);
}
EditorLooper::~EditorLooper()
{
fEditor.StopWatching(this);
}
void
EditorLooper::MessageReceived(BMessage* message)
{
switch (message->what) {
case kMsgPositionUpdate:
{
if (Looper()->MessageQueue()->FindMessage(kMsgPositionUpdate, 0) != NULL)
break;
off_t position;
if (message->FindInt64("position", &position) == B_OK) {
BAutolock locker(fEditor);
fEditor.SetViewOffset(position);
BMessage message(kMsgSetSelection);
message.AddInt64("start", position - fEditor.ViewOffset());
message.AddInt64("end", position - fEditor.ViewOffset());
fMessenger.SendMessage(&message);
}
break;
}
case kMsgDataEditorParameterChange:
{
bool updated = false;
if (fEditor.Lock()) {
fEditor.UpdateIfNeeded(&updated);
fEditor.Unlock();
}
if (updated) {
BMessage reply;
fMessenger.SendMessage(kMsgUpdateData, &reply);
}
break;
}
case kMsgFind:
{
BMessenger progressMonitor;
message->FindMessenger("progress_monitor", &progressMonitor);
off_t startAt = 0;
message->FindInt64("start", &startAt);
bool caseInsensitive = !message->FindBool("case_sensitive");
ssize_t dataSize;
const uint8* data;
if (message->FindData("data", B_RAW_TYPE, (const void**)&data,
&dataSize) == B_OK)
Find(startAt, data, dataSize, caseInsensitive, progressMonitor);
}
default:
BLooper::MessageReceived(message);
break;
}
}
void
EditorLooper::Find(off_t startAt, const uint8* data, size_t dataSize,
bool caseInsensitive, BMessenger progressMonitor)
{
fQuitFind = false;
BAutolock locker(fEditor);
bigtime_t startTime = system_time();
off_t foundAt = fEditor.Find(startAt, data, dataSize, caseInsensitive,
true, progressMonitor, &fQuitFind);
if (foundAt >= B_OK) {
fEditor.SetViewOffset(foundAt);
BMessage message(kMsgSetSelection);
message.AddInt64("start", foundAt - fEditor.ViewOffset());
message.AddInt64("end", foundAt + dataSize - 1 - fEditor.ViewOffset());
fMessenger.SendMessage(&message);
} else if (foundAt == B_ENTRY_NOT_FOUND) {
if (system_time() > startTime + 8000000LL) {
BAlert* alert = new BAlert(B_TRANSLATE("DiskProbe request"),
B_TRANSLATE("Could not find search string."),
B_TRANSLATE("OK"), NULL, NULL, B_WIDTH_AS_USUAL,
B_WARNING_ALERT);
alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
alert->Go(NULL);
} else
beep();
}
}
void
EditorLooper::QuitFind()
{
fQuitFind = true;
}
TypeView::TypeView(const char* name, int32 index, DataEditor& editor)
: BView(name, B_FRAME_EVENTS)
{
SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
fTypeEditorView = GetTypeEditorAt(index, editor);
if (fTypeEditorView == NULL) {
fTypeEditorView = new BStringView(B_TRANSLATE("Type editor"),
B_TRANSLATE("Type editor not supported"));
}
BLayoutBuilder::Group<>(this, B_VERTICAL)
.Add(fTypeEditorView);
}
TypeView::~TypeView()
{
}
ProbeView::ProbeView(entry_ref* ref, const char* attribute,
const BMessage* settings)
: BView("probeView", B_WILL_DRAW),
fPrintSettings(NULL),
fTypeView(NULL),
fLastSearch(NULL)
{
fEditor.SetTo(*ref, attribute);
int32 baseType = kHexBase;
float fontSize = be_plain_font->Size();
if (settings != NULL) {
settings->FindInt32("base_type", &baseType);
settings->FindFloat("font_size", &fontSize);
}
fHeaderView = new HeaderView(&fEditor.Ref(), fEditor);
fHeaderView->SetBase((base_type)baseType);
fDataView = new DataView(fEditor);
fDataView->SetBase((base_type)baseType);
fDataView->SetFontSize(fontSize);
fScrollView = new BScrollView("scroller", fDataView, B_WILL_DRAW, true,
true);
BLayoutBuilder::Group<>(this, B_VERTICAL, 0)
.SetInsets(-1, -1, -1, -1)
.Add(fHeaderView)
.AddGroup(B_VERTICAL, 0)
.SetInsets(-1, 0, -1, -1)
.Add(fScrollView)
.End();
fDataView->UpdateScroller();
}
ProbeView::~ProbeView()
{
}
void
ProbeView::DetachedFromWindow()
{
fEditorLooper->QuitFind();
if (fEditorLooper->Lock())
fEditorLooper->Quit();
fEditorLooper = NULL;
fEditor.StopWatching(this);
fDataView->StopWatching(fHeaderView, kDataViewCursorPosition);
fDataView->StopWatching(this, kDataViewSelection);
fDataView->StopWatching(this, kDataViewPreferredSize);
be_clipboard->StopWatching(this);
}
void
ProbeView::_UpdateAttributesMenu(BMenu* menu)
{
for (int32 i = menu->CountItems(); i-- > 0;) {
delete menu->RemoveItem(i);
}
BNode node(&fEditor.AttributeRef());
if (node.InitCheck() == B_OK) {
char attribute[B_ATTR_NAME_LENGTH];
node.RewindAttrs();
while (node.GetNextAttrName(attribute) == B_OK) {
attr_info info;
if (node.GetAttrInfo(attribute, &info) != B_OK)
continue;
char type[16];
type[0] = '[';
get_type_string(type + 1, sizeof(type) - 2, info.type);
strcat(type, "]");
int32 i;
for (i = 0; i < menu->CountItems(); i++) {
if (strcasecmp(menu->ItemAt(i)->Label(), attribute) > 0)
break;
}
BMessage* message = new BMessage(B_REFS_RECEIVED);
message->AddRef("refs", &fEditor.AttributeRef());
message->AddString("attributes", attribute);
menu->AddItem(new TypeMenuItem(attribute, type, message), i);
}
}
if (menu->CountItems() == 0) {
BMenuItem* item = new BMenuItem(B_TRANSLATE_COMMENT("none",
"No attributes"), NULL);
item->SetEnabled(false);
menu->AddItem(item);
}
menu->SetTargetForItems(be_app);
}
void
ProbeView::AddSaveMenuItems(BMenu* menu, int32 index)
{
menu->AddItem(fSaveMenuItem = new BMenuItem(B_TRANSLATE("Save"),
new BMessage(B_SAVE_REQUESTED), 'S'), index);
fSaveMenuItem->SetTarget(this);
fSaveMenuItem->SetEnabled(false);
}
void
ProbeView::AddPrintMenuItems(BMenu* menu, int32 index)
{
BMenuItem* item;
menu->AddItem(item = new BMenuItem(B_TRANSLATE("Page setup" B_UTF8_ELLIPSIS),
new BMessage(kMsgPageSetup)), index++);
item->SetTarget(this);
menu->AddItem(item = new BMenuItem(B_TRANSLATE("Print" B_UTF8_ELLIPSIS),
new BMessage(kMsgPrint), 'P'), index++);
item->SetTarget(this);
}
void
ProbeView::AddViewAsMenuItems()
{
#if 0
BMenuBar* bar = Window()->KeyMenuBar();
if (bar == NULL)
return;
BMenuItem* item = bar->FindItem(B_TRANSLATE("View"));
BMenu* menu = NULL;
if (item != NULL)
menu = item->Submenu();
else
menu = bar->SubmenuAt(bar->CountItems() - 1);
if (menu == NULL)
return;
menu->AddSeparatorItem();
BMenu* subMenu = new BMenu(B_TRANSLATE("View As"));
subMenu->SetRadioMode(true);
BMessage* message = new BMessage(kMsgViewAs);
subMenu->AddItem(item = new BMenuItem(B_TRANSLATE("Raw"), message));
item->SetMarked(true);
const char* name;
for (int32 i = 0; GetNthTypeEditor(i, &name) == B_OK; i++) {
message = new BMessage(kMsgViewAs);
message->AddInt32("editor index", i);
subMenu->AddItem(new BMenuItem(name, message));
}
subMenu->SetTargetForItems(this);
menu->AddItem(new BMenuItem(subMenu));
#endif
}
void
ProbeView::AttachedToWindow()
{
BView::AttachedToWindow();
fEditorLooper = new EditorLooper(fEditor.Ref().name, fEditor,
BMessenger(fDataView));
fEditorLooper->Run();
fEditor.StartWatching(this);
fDataView->StartWatching(fHeaderView, kDataViewCursorPosition);
fDataView->StartWatching(this, kDataViewSelection);
fDataView->StartWatching(this, kDataViewPreferredSize);
be_clipboard->StartWatching(this);
BMenuBar* bar = Window()->KeyMenuBar();
if (bar == NULL) {
bar = new BMenuBar("");
Window()->AddChild(bar);
BMenu* menu = new BMenu(fEditor.IsAttribute()
? B_TRANSLATE("Attribute") : fEditor.IsDevice()
? B_TRANSLATE("Device") : B_TRANSLATE("File"));
AddSaveMenuItems(menu, 0);
menu->AddSeparatorItem();
AddPrintMenuItems(menu, menu->CountItems());
menu->AddSeparatorItem();
menu->AddItem(new BMenuItem(B_TRANSLATE("Close"),
new BMessage(B_CLOSE_REQUESTED), 'W'));
bar->AddItem(menu);
}
BMenu* menu = new BMenu(B_TRANSLATE("Edit"));
BMenuItem* item;
menu->AddItem(fUndoMenuItem = new BMenuItem(B_TRANSLATE("Undo"),
new BMessage(B_UNDO), 'Z'));
fUndoMenuItem->SetEnabled(fEditor.CanUndo());
fUndoMenuItem->SetTarget(fDataView);
menu->AddItem(fRedoMenuItem = new BMenuItem(B_TRANSLATE("Redo"),
new BMessage(B_REDO), 'Z', B_SHIFT_KEY));
fRedoMenuItem->SetEnabled(fEditor.CanRedo());
fRedoMenuItem->SetTarget(fDataView);
menu->AddSeparatorItem();
menu->AddItem(item = new BMenuItem(B_TRANSLATE("Copy"),
new BMessage(B_COPY), 'C'));
item->SetTarget(NULL, Window());
menu->AddItem(fPasteMenuItem = new BMenuItem(B_TRANSLATE("Paste"),
new BMessage(B_PASTE), 'V'));
fPasteMenuItem->SetTarget(NULL, Window());
_CheckClipboard();
menu->AddItem(item = new BMenuItem(B_TRANSLATE("Select all"),
new BMessage(B_SELECT_ALL), 'A'));
item->SetTarget(NULL, Window());
menu->AddSeparatorItem();
menu->AddItem(item = new BMenuItem(B_TRANSLATE("Find" B_UTF8_ELLIPSIS),
new BMessage(kMsgOpenFindWindow), 'F'));
item->SetTarget(this);
menu->AddItem(fFindAgainMenuItem = new BMenuItem(B_TRANSLATE("Find again"),
new BMessage(kMsgFind), 'G'));
fFindAgainMenuItem->SetEnabled(false);
fFindAgainMenuItem->SetTarget(this);
bar->AddItem(menu);
menu = new BMenu(B_TRANSLATE("Block"));
BMessage* message = new BMessage(kMsgPositionUpdate);
message->AddInt32("delta", 1);
menu->AddItem(item = new BMenuItem(B_TRANSLATE("Next"), message,
B_RIGHT_ARROW));
item->SetTarget(fHeaderView);
message = new BMessage(kMsgPositionUpdate);
message->AddInt32("delta", -1);
menu->AddItem(item = new BMenuItem(B_TRANSLATE("Previous"), message,
B_LEFT_ARROW));
item->SetTarget(fHeaderView);
menu->AddItem(item = new BMenuItem(B_TRANSLATE("Back"),
new BMessage(kMsgLastPosition), 'J'));
item->SetTarget(fHeaderView);
BMenu* subMenu = new BMenu(B_TRANSLATE("Selection"));
message = new BMessage(kMsgPositionUpdate);
message->AddInt64("block", 0);
subMenu->AddItem(fNativeMenuItem = new BMenuItem("", message, 'K'));
fNativeMenuItem->SetTarget(fHeaderView);
message = new BMessage(*message);
subMenu->AddItem(fSwappedMenuItem = new BMenuItem("", message, 'L'));
fSwappedMenuItem->SetTarget(fHeaderView);
menu->AddItem(new BMenuItem(subMenu));
_UpdateSelectionMenuItems(0, 0);
menu->AddSeparatorItem();
fBookmarkMenu = new BMenu(B_TRANSLATE("Bookmarks"));
fBookmarkMenu->AddItem(item = new BMenuItem(B_TRANSLATE("Add"),
new BMessage(kMsgAddBookmark), 'B'));
item->SetTarget(this);
menu->AddItem(new BMenuItem(fBookmarkMenu));
bar->AddItem(menu);
BDirectory directory;
BVolume volume;
if (directory.SetTo(&fEditor.AttributeRef()) == B_OK
&& directory.IsRootDirectory())
directory.GetVolume(&volume);
else
fEditor.File().GetVolume(&volume);
if (!fEditor.IsAttribute() && volume.InitCheck() == B_OK
&& (volume.KnowsMime() || volume.KnowsAttr())) {
bar->AddItem(menu = new BMenu(B_TRANSLATE("Attributes")));
_UpdateAttributesMenu(menu);
}
menu = new BMenu(B_TRANSLATE_COMMENT("View",
"This is the last menubar item 'File Edit Block View'"));
subMenu = new BMenu(B_TRANSLATE_COMMENT("Base", "A menu item, the number "
"that is basis for a system of calculation. The base 10 system is a "
"decimal system. This is in the same menu window than 'Font size' "
"and 'BlockSize'"));
message = new BMessage(kMsgBaseType);
message->AddInt32("base_type", kDecimalBase);
subMenu->AddItem(item = new BMenuItem(B_TRANSLATE_COMMENT("Decimal",
"A menu item, as short as possible, noun is recommended if it is "
"shorter than adjective."), message, 'D'));
item->SetTarget(this);
if (fHeaderView->Base() == kDecimalBase)
item->SetMarked(true);
message = new BMessage(kMsgBaseType);
message->AddInt32("base_type", kHexBase);
subMenu->AddItem(item = new BMenuItem(B_TRANSLATE_COMMENT("Hex",
"A menu item, as short as possible, noun is recommended if it is "
"shorter than adjective."), message, 'H'));
item->SetTarget(this);
if (fHeaderView->Base() == kHexBase)
item->SetMarked(true);
subMenu->SetRadioMode(true);
menu->AddItem(new BMenuItem(subMenu));
subMenu = new BMenu(B_TRANSLATE_COMMENT("Block size", "Menu item. "
"This is in the same menu window than 'Base' and 'Font size'"));
subMenu->SetRadioMode(true);
const uint32 blockSizes[] = {512, 1024, 2048, 4096};
for (uint32 i = 0; i < sizeof(blockSizes) / sizeof(blockSizes[0]); i++) {
char buffer[32];
snprintf(buffer, sizeof(buffer), "%" B_PRId32 "%s", blockSizes[i],
fEditor.IsDevice() && fEditor.BlockSize() == blockSizes[i]
? B_TRANSLATE(" (native)") : "");
subMenu->AddItem(item = new BMenuItem(buffer,
message = new BMessage(kMsgBlockSize)));
message->AddInt32("block_size", blockSizes[i]);
if (fEditor.BlockSize() == blockSizes[i])
item->SetMarked(true);
}
if (subMenu->FindMarked() == NULL) {
char buffer[32];
snprintf(buffer, sizeof(buffer), B_TRANSLATE("%ld (native)"),
fEditor.BlockSize());
subMenu->AddItem(item = new BMenuItem(buffer,
message = new BMessage(kMsgBlockSize)));
message->AddInt32("block_size", fEditor.BlockSize());
item->SetMarked(true);
}
subMenu->SetTargetForItems(this);
menu->AddItem(new BMenuItem(subMenu));
menu->AddSeparatorItem();
subMenu = new BMenu(B_TRANSLATE("Font size"));
subMenu->SetRadioMode(true);
const int32 fontSizes[] = {9, 10, 11, 12, 13, 14, 18, 24, 36, 48};
int32 fontSize = int32(fDataView->FontSize() + 0.5);
if (fDataView->FontSizeFitsBounds())
fontSize = 0;
for (uint32 i = 0; i < sizeof(fontSizes) / sizeof(fontSizes[0]); i++) {
char buffer[16];
snprintf(buffer, sizeof(buffer), "%" B_PRId32, fontSizes[i]);
subMenu->AddItem(item = new BMenuItem(buffer,
message = new BMessage(kMsgFontSize)));
message->AddFloat("font_size", fontSizes[i]);
if (fontSizes[i] == fontSize)
item->SetMarked(true);
}
subMenu->AddSeparatorItem();
subMenu->AddItem(item = new BMenuItem(B_TRANSLATE_COMMENT("Fit",
"Size of fonts, fits to available room"),
message = new BMessage(kMsgFontSize)));
message->AddFloat("font_size", 0.0f);
if (fontSize == 0)
item->SetMarked(true);
subMenu->SetTargetForItems(this);
menu->AddItem(new BMenuItem(subMenu));
bar->AddItem(menu);
}
void
ProbeView::AllAttached()
{
fHeaderView->SetTarget(fEditorLooper);
}
void
ProbeView::WindowActivated(bool active)
{
if (!active)
return;
fDataView->MakeFocus(true);
BMessage target(kMsgFindTarget);
target.AddMessenger("target", this);
be_app_messenger.SendMessage(&target);
}
void
ProbeView::_UpdateSelectionMenuItems(int64 start, int64 end)
{
int64 position = 0;
const uint8* data = fDataView->DataAt(start);
if (data == NULL) {
fNativeMenuItem->SetEnabled(false);
fSwappedMenuItem->SetEnabled(false);
return;
}
int size;
if (end < start + 8)
size = end + 1 - start;
else
size = 8;
int64 bigEndianPosition = 0;
memcpy(&bigEndianPosition, data, size);
position = B_BENDIAN_TO_HOST_INT64(bigEndianPosition) >> (8 * (8 - size));
char buffer[128];
if (fDataView->Base() == kHexBase) {
snprintf(buffer, sizeof(buffer), B_TRANSLATE("Native: 0x%0*Lx"),
size * 2, (long long int)position);
} else {
snprintf(buffer, sizeof(buffer), B_TRANSLATE("Native: %lld (0x%0*Lx)"),
(long long int)position, size * 2, (long long int)position);
}
fNativeMenuItem->SetLabel(buffer);
fNativeMenuItem->SetEnabled(position >= 0
&& (off_t)(position * fEditor.BlockSize()) < fEditor.FileSize());
fNativeMenuItem->Message()->ReplaceInt64("block", position);
position = B_SWAP_INT64(position) >> (8 * (8 - size));
if (fDataView->Base() == kHexBase) {
snprintf(buffer, sizeof(buffer), B_TRANSLATE("Swapped: 0x%0*Lx"),
size * 2, (long long int)position);
} else {
snprintf(buffer, sizeof(buffer), B_TRANSLATE("Swapped: %lld (0x%0*Lx)"),
(long long int)position, size * 2, (long long int)position);
}
fSwappedMenuItem->SetLabel(buffer);
fSwappedMenuItem->SetEnabled(position >= 0 && (off_t)(position * fEditor.BlockSize()) < fEditor.FileSize());
fSwappedMenuItem->Message()->ReplaceInt64("block", position);
}
void
ProbeView::_UpdateBookmarkMenuItems()
{
for (int32 i = 2; i < fBookmarkMenu->CountItems(); i++) {
BMenuItem* item = fBookmarkMenu->ItemAt(i);
if (item == NULL)
break;
BMessage* message = item->Message();
if (message == NULL)
break;
off_t block = message->FindInt64("block");
char buffer[128];
if (fDataView->Base() == kHexBase)
snprintf(buffer, sizeof(buffer), B_TRANSLATE("Block 0x%Lx"), (long long unsigned)block);
else {
snprintf(buffer, sizeof(buffer), B_TRANSLATE("Block %lld (0x%Lx)"),
(long long int)block, (long long unsigned)block);
}
item->SetLabel(buffer);
}
}
void
ProbeView::_AddBookmark(off_t position)
{
int32 count = fBookmarkMenu->CountItems();
if (count == 1) {
fBookmarkMenu->AddSeparatorItem();
count++;
}
off_t block = position / fEditor.BlockSize();
off_t bookmark = -1;
BMenuItem* item;
int32 i;
for (i = 2; (item = fBookmarkMenu->ItemAt(i)) != NULL; i++) {
BMessage* message = item->Message();
if (message != NULL && message->FindInt64("block", &bookmark) == B_OK) {
if (block <= bookmark)
break;
}
}
if (block == bookmark)
return;
char buffer[128];
if (fDataView->Base() == kHexBase)
snprintf(buffer, sizeof(buffer), B_TRANSLATE("Block 0x%Lx"), (long long unsigned)block);
else {
snprintf(buffer, sizeof(buffer), B_TRANSLATE("Block %lld (0x%Lx)"),
(long long int)block, (long long unsigned)block);
}
BMessage* message;
item = new BMenuItem(buffer, message = new BMessage(kMsgPositionUpdate));
item->SetTarget(fHeaderView);
if (count < 12)
item->SetShortcut('0' + count - 2, B_COMMAND_KEY);
message->AddInt64("block", block);
fBookmarkMenu->AddItem(item, i);
}
void
ProbeView::_RemoveTypeEditor()
{
if (fTypeView == NULL)
return;
if (Parent() != NULL)
Parent()->RemoveChild(fTypeView);
else
Window()->RemoveChild(fTypeView);
delete fTypeView;
fTypeView = NULL;
}
void
ProbeView::_SetTypeEditor(int32 index)
{
if (index == -1) {
if (IsHidden())
Show();
_RemoveTypeEditor();
} else {
if (!IsHidden())
Hide();
_RemoveTypeEditor();
fTypeView = new TypeView("type shell", index, fEditor);
if (Parent() != NULL)
Parent()->GetLayout()->AddView(fTypeView);
else
Window()->GetLayout()->AddView(fTypeView);
}
}
void
ProbeView::_CheckClipboard()
{
if (!be_clipboard->Lock())
return;
bool hasData = false;
BMessage* clip;
if ((clip = be_clipboard->Data()) != NULL) {
const void* data;
ssize_t size;
if (clip->FindData(B_FILE_MIME_TYPE, B_MIME_TYPE, &data, &size) == B_OK
|| clip->FindData("text/plain", B_MIME_TYPE, &data, &size) == B_OK)
hasData = true;
}
be_clipboard->Unlock();
fPasteMenuItem->SetEnabled(hasData);
}
status_t
ProbeView::_PageSetup()
{
BPrintJob printJob(Window()->Title());
if (fPrintSettings != NULL)
printJob.SetSettings(new BMessage(*fPrintSettings));
status_t status = printJob.ConfigPage();
if (status == B_OK) {
delete fPrintSettings;
fPrintSettings = printJob.Settings();
}
return status;
}
void
ProbeView::_Print()
{
if (fPrintSettings == NULL && _PageSetup() != B_OK)
return;
BPrintJob printJob(Window()->Title());
printJob.SetSettings(new BMessage(*fPrintSettings));
if (printJob.ConfigJob() == B_OK) {
BRect rect = printJob.PrintableRect();
float width, height;
fDataView->GetPreferredSize(&width, &height);
printJob.BeginJob();
fDataView->SetScale(rect.Width() / width);
printJob.DrawView(fDataView, rect, rect.LeftTop());
fDataView->SetScale(1.0);
printJob.SpoolPage();
printJob.CommitJob();
}
}
status_t
ProbeView::_Save()
{
status_t status = fEditor.Save();
if (status == B_OK)
return B_OK;
char buffer[1024];
snprintf(buffer, sizeof(buffer),
B_TRANSLATE("Writing to the file failed:\n"
"%s\n\n"
"All changes will be lost when you quit."),
strerror(status));
BAlert* alert = new BAlert(B_TRANSLATE("DiskProbe request"),
buffer, B_TRANSLATE("OK"), NULL, NULL,
B_WIDTH_AS_USUAL, B_WARNING_ALERT);
alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
alert->Go(NULL);
return status;
}
bool
ProbeView::QuitRequested()
{
fEditorLooper->QuitFind();
if (!fEditor.IsModified())
return true;
BAlert* alert = new BAlert(B_TRANSLATE("DiskProbe request"),
B_TRANSLATE("Save changes before closing?"), B_TRANSLATE("Cancel"),
B_TRANSLATE("Don't save"), B_TRANSLATE("Save"), B_WIDTH_AS_USUAL,
B_OFFSET_SPACING, B_WARNING_ALERT);
alert->SetShortcut(0, B_ESCAPE);
alert->SetShortcut(1, 'd');
alert->SetShortcut(2, 's');
int32 chosen = alert->Go();
if (chosen == 0)
return false;
if (chosen == 1)
return true;
return _Save() == B_OK;
}
void
ProbeView::MessageReceived(BMessage* message)
{
switch (message->what) {
case B_SAVE_REQUESTED:
_Save();
break;
case B_OBSERVER_NOTICE_CHANGE: {
int32 what;
if (message->FindInt32(B_OBSERVE_WHAT_CHANGE, &what) != B_OK)
break;
switch (what) {
case kDataViewSelection:
{
int64 start, end;
if (message->FindInt64("start", &start) == B_OK
&& message->FindInt64("end", &end) == B_OK)
_UpdateSelectionMenuItems(start, end);
break;
}
}
break;
}
case kMsgBaseType:
{
int32 type;
if (message->FindInt32("base_type", &type) != B_OK)
break;
fHeaderView->SetBase((base_type)type);
fDataView->SetBase((base_type)type);
int32 start, end;
fDataView->GetSelection(start, end);
_UpdateSelectionMenuItems(start, end);
_UpdateBookmarkMenuItems();
BMessage update(*message);
update.what = kMsgSettingsChanged;
be_app_messenger.SendMessage(&update);
break;
}
case kMsgFontSize:
{
float size;
if (message->FindFloat("font_size", &size) != B_OK)
break;
fDataView->SetFontSize(size);
BMessage update(*message);
update.what = kMsgSettingsChanged;
be_app_messenger.SendMessage(&update);
break;
}
case kMsgBlockSize:
{
int32 blockSize;
if (message->FindInt32("block_size", &blockSize) != B_OK)
break;
BAutolock locker(fEditor);
if (fEditor.SetViewSize(blockSize) == B_OK
&& fEditor.SetBlockSize(blockSize) == B_OK)
fHeaderView->SetTo(fEditor.ViewOffset(), blockSize);
break;
}
case kMsgViewAs:
{
int32 index;
if (message->FindInt32("editor index", &index) != B_OK)
index = -1;
_SetTypeEditor(index);
break;
}
case kMsgAddBookmark:
_AddBookmark(fHeaderView->Position());
break;
case kMsgPrint:
_Print();
break;
case kMsgPageSetup:
_PageSetup();
break;
case kMsgOpenFindWindow:
{
fEditorLooper->QuitFind();
BMessage find(*fFindAgainMenuItem->Message());
find.what = kMsgOpenFindWindow;
find.AddMessenger("target", this);
be_app_messenger.SendMessage(&find);
break;
}
case kMsgFind:
{
const uint8* data;
ssize_t size;
if (message->FindData("data", B_RAW_TYPE, (const void**)&data,
&size) != B_OK) {
BMessage* itemMessage = fFindAgainMenuItem->Message();
if (itemMessage == NULL || itemMessage->FindData("data",
B_RAW_TYPE, (const void**)&data, &size) != B_OK) {
beep();
break;
}
} else {
fFindAgainMenuItem->SetMessage(new BMessage(*message));
fFindAgainMenuItem->SetEnabled(true);
}
int32 start, end;
fDataView->GetSelection(start, end);
BMessage find(*message);
find.AddInt64("start", fHeaderView->Position() + start + 1);
find.AddMessenger("progress_monitor", BMessenger(fHeaderView));
fEditorLooper->PostMessage(&find);
break;
}
case kMsgStopFind:
fEditorLooper->QuitFind();
break;
case B_NODE_MONITOR:
{
switch (message->FindInt32("opcode")) {
case B_STAT_CHANGED:
fEditor.ForceUpdate();
break;
case B_ATTR_CHANGED:
{
const char* name;
if (message->FindString("attr", &name) != B_OK)
break;
if (fEditor.IsAttribute()) {
if (!strcmp(name, fEditor.Attribute()))
fEditor.ForceUpdate();
} else {
BMenuBar* bar = Window()->KeyMenuBar();
if (bar != NULL) {
BMenuItem* item = bar->FindItem("Attributes");
if (item != NULL && item->Submenu() != NULL)
_UpdateAttributesMenu(item->Submenu());
}
}
if (!strcmp(name, "BEOS:TYPE")
|| !strcmp(name, "BEOS:M:STD_ICON")
|| !strcmp(name, "BEOS:L:STD_ICON")
|| !strcmp(name, "BEOS:ICON"))
fHeaderView->UpdateIcon();
break;
}
}
break;
}
case B_CLIPBOARD_CHANGED:
_CheckClipboard();
break;
case kMsgDataEditorStateChange:
{
bool enabled;
if (message->FindBool("can_undo", &enabled) == B_OK)
fUndoMenuItem->SetEnabled(enabled);
if (message->FindBool("can_redo", &enabled) == B_OK)
fRedoMenuItem->SetEnabled(enabled);
if (message->FindBool("modified", &enabled) == B_OK)
fSaveMenuItem->SetEnabled(enabled);
break;
}
default:
BView::MessageReceived(message);
}
}