diff --git a/src/apps/diskprobe/DiskProbe.cpp b/src/apps/diskprobe/DiskProbe.cpp index 6cc67190bd..60e2711aed 100644 --- a/src/apps/diskprobe/DiskProbe.cpp +++ b/src/apps/diskprobe/DiskProbe.cpp @@ -10,6 +10,7 @@ #include "FileWindow.h" #include "AttributeWindow.h" #include "OpenWindow.h" +#include "FindWindow.h" #include #include @@ -76,8 +77,10 @@ class DiskProbe : public BApplication { Settings fSettings; BFilePanel *fFilePanel; BWindow *fOpenWindow; + FindWindow *fFindWindow; uint32 fWindowCount; BRect fWindowFrame; + BMessenger fFindTarget; }; @@ -192,6 +195,7 @@ Settings::UpdateFrom(BMessage *message) DiskProbe::DiskProbe() : BApplication(kSignature), fOpenWindow(NULL), + fFindWindow(NULL), fWindowCount(0) { fFilePanel = new BFilePanel(); @@ -360,6 +364,36 @@ DiskProbe::MessageReceived(BMessage *message) fSettings.UpdateFrom(message); break; + case kMsgFindWindowClosed: + fFindWindow = NULL; + break; + case kMsgFindTarget: + { + BMessenger target; + if (message->FindMessenger("target", &target) != B_OK) + break; + + if (fFindWindow != NULL && fFindWindow->Lock()) { + fFindWindow->SetTarget(target); + fFindWindow->Unlock(); + } + break; + } + case kMsgOpenFindWindow: + { + BMessenger target; + if (message->FindMessenger("target", &target) != B_OK) + break; + + if (fFindWindow == NULL) { + // open it! + fFindWindow = new FindWindow(fWindowFrame.OffsetByCopy(80, 80), target); + fFindWindow->Show(); + } else + fFindWindow->Activate(); + break; + } + case kMsgOpenFilePanel: fFilePanel->Show(); break; diff --git a/src/apps/diskprobe/DiskProbe.h b/src/apps/diskprobe/DiskProbe.h index 79ff10d7b6..3aee901fcc 100644 --- a/src/apps/diskprobe/DiskProbe.h +++ b/src/apps/diskprobe/DiskProbe.h @@ -17,4 +17,9 @@ static const uint32 kMsgOpenWindowClosed = 'clOw'; static const uint32 kMsgWindowClosed = 'WiCl'; static const uint32 kMsgSettingsChanged = 'SeCh'; +static const uint32 kMsgOpenFindWindow = 'OpFw'; +static const uint32 kMsgFindWindowClosed = 'clFw'; +static const uint32 kMsgFindTarget = 'FTgt'; +static const uint32 kMsgFind = 'find'; + #endif /* DISK_PROBE_H */ diff --git a/src/apps/diskprobe/FindWindow.cpp b/src/apps/diskprobe/FindWindow.cpp new file mode 100644 index 0000000000..a61088c3eb --- /dev/null +++ b/src/apps/diskprobe/FindWindow.cpp @@ -0,0 +1,335 @@ +/* +** Copyright 2004, Axel Dörfler, axeld@pinc-software.de. All rights reserved. +** Distributed under the terms of the OpenBeOS License. +*/ + + +#include "FindWindow.h" +#include "DiskProbe.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + + +enum find_mode { + kAsciiMode, + kHexMode +}; + +static const uint32 kMsgFindMode = 'FMde'; +static const uint32 kMsgStartFind = 'SFnd'; + + +class FindTextView : public BTextView { + public: + FindTextView(BRect frame, const char *name, BRect textRect, uint32 resizeMask); + + virtual void MakeFocus(bool state); + virtual void TargetedByScrollView(BScrollView *view); + + status_t SetMode(find_mode mode); + void GetData(BMessage &message); + + virtual void KeyDown(const char *bytes, int32 numBytes); + + protected: + virtual void InsertText(const char *text, int32 length, + int32 offset, const text_run_array *runs); + + private: + BScrollView *fScrollView; + find_mode fMode; +}; + + +//--------------- + + +FindTextView::FindTextView(BRect frame, const char *name, BRect textRect, + uint32 resizeMask) + : BTextView(frame, name, textRect, resizeMask), + fScrollView(NULL), + fMode(kAsciiMode) +{ +} + + +void +FindTextView::MakeFocus(bool state) +{ + BTextView::MakeFocus(state); + + if (fScrollView != NULL) + fScrollView->SetBorderHighlighted(state); +} + + +void +FindTextView::TargetedByScrollView(BScrollView *view) +{ + BTextView::TargetedByScrollView(view); + fScrollView = view; +} + + +void +FindTextView::KeyDown(const char *bytes, int32 numBytes) +{ + if (fMode == kHexMode) { + // filter out invalid characters + if (numBytes > 1) + return; + + if (bytes[0] == B_DELETE || bytes[0] == B_BACKSPACE) { + // ToDo + return; + } + + if (!strchr("0123456789abcdefABCDEF", bytes[0])) + return; + + // the original KeyDown() has severe cursor setting + // problems with our InsertText(). + + int32 start, end; + GetSelection(&start, &end); + InsertText(bytes, 1, start, NULL); + Invalidate(); + return; + } + BTextView::KeyDown(bytes, numBytes); +} + + +void +FindTextView::InsertText(const char *text, int32 length, int32 offset, + const text_run_array *runs) +{ + if (fMode == kHexMode) { + if (offset > TextLength()) + offset = TextLength(); + + BTextView::InsertText(text, length, offset, runs); + // lets add anything, and then start to filter out + // (since we have to reformat the whole text) + + const char *text = Text(); + int32 textLength = TextLength(); + char *insert = (char *)malloc(textLength * 2); + if (insert == NULL) + return; + + int32 cursor = TextLength(); + int32 out = 0; + for (int32 i = 0; i < textLength; i++) { + char c = text[i]; + if (c >= 'A' && c <= 'F') + c += 'A' - 'a'; + if ((c >= 'a' && c <= 'f') || (c >= '0' && c <= '9')) + insert[out++] = c; + + if (i == offset && length == 1) { + // this is the end of the inserted text + cursor = out; + } + + if ((out % 3) == 2) + insert[out++] = ' '; + } + insert[out] = '\0'; + + DeleteText(0, textLength); + BTextView::InsertText(insert, out, 0, NULL); + + int32 start, end; + GetSelection(&start, &end); + if (start == offset) + Select(cursor, cursor); + + free(insert); + } else + BTextView::InsertText(text, length, offset, runs); +} + + +status_t +FindTextView::SetMode(find_mode mode) +{ + if (fMode == mode) + return B_OK; + + if (mode == kHexMode) { + // convert text to hex mode + + int32 length = TextLength(); + char *hex = (char *)malloc(length * 3 + 1); + if (hex == NULL) + return B_NO_MEMORY; + + fMode = mode; + + const char *text = Text(); + char *out = hex; + for (int32 i = 0; i < length; i++) { + out += sprintf(out, "%02x", *(unsigned char *)(text + i)); + } + out[0] = '\0'; + SetText(hex); + free(hex); + } else { + // ToDo: convert to ascii + return B_ERROR; + } + + return B_OK; +} + + +void +FindTextView::GetData(BMessage &message) +{ + if (fMode == kHexMode) { + // ToDo: ... + } else + message.AddData("data", B_RAW_TYPE, Text(), TextLength()); +} + + +// #pragma mark - + + +FindWindow::FindWindow(BRect rect, BMessenger &target) + : BWindow(rect, "Find", B_TITLED_WINDOW, B_ASYNCHRONOUS_CONTROLS), + fTarget(target) +{ + BView *view = new BView(Bounds(), "main", B_FOLLOW_ALL, 0); + view->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); + AddChild(view); + + // add the top widgets + + fMenu = new BPopUpMenu("mode"); + BMessage *message; + BMenuItem *item; + fMenu->AddItem(item = new BMenuItem("String", message = new BMessage(kMsgFindMode))); + item->SetMarked(true); + message->AddInt8("mode", kAsciiMode); + fMenu->AddItem(item = new BMenuItem("Hexadecimal", message = new BMessage(kMsgFindMode))); + message->AddInt8("mode", kHexMode); + + BRect rect = Bounds().InsetByCopy(5, 5); + BMenuField *menuField = new BMenuField(rect, B_EMPTY_STRING, + "Mode:", fMenu, B_FOLLOW_LEFT | B_FOLLOW_TOP); + menuField->SetDivider(menuField->StringWidth(menuField->Label()) + 8); + menuField->ResizeToPreferred(); + view->AddChild(menuField); + + // add the bottom widgets + + BButton *button = new BButton(rect, B_EMPTY_STRING, "Find", new BMessage(kMsgStartFind), + B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM); + button->MakeDefault(true); + button->ResizeToPreferred(); + button->MoveTo(rect.right - button->Bounds().Width(), + rect.bottom - button->Bounds().Height()); + view->AddChild(button); + + fCaseCheckBox = new BCheckBox(rect, B_EMPTY_STRING, "Case sensitive", + NULL, B_FOLLOW_LEFT | B_FOLLOW_BOTTOM); + fCaseCheckBox->ResizeToPreferred(); + fCaseCheckBox->MoveTo(5, button->Frame().top - 5 - fCaseCheckBox->Bounds().Height()); + view->AddChild(fCaseCheckBox); + + // and now those inbetween + + rect.top = menuField->Frame().bottom + 5; + rect.bottom = fCaseCheckBox->Frame().top - 5; + rect.InsetBy(2, 2); + fTextView = new FindTextView(rect, B_EMPTY_STRING, + rect.OffsetToCopy(B_ORIGIN).InsetByCopy(3, 3), + B_FOLLOW_ALL); + fTextView->SetWordWrap(true); + + BScrollView *scrollView = new BScrollView("scroller", fTextView, B_FOLLOW_ALL, B_WILL_DRAW, false, false); + view->AddChild(scrollView); + + ResizeTo(290, button->Frame().Height() * 4 + 30); +} + + +FindWindow::~FindWindow() +{ +} + + +void +FindWindow::WindowActivated(bool active) +{ + fTextView->MakeFocus(active); +} + + +void +FindWindow::MessageReceived(BMessage *message) +{ + switch (message->what) { + case kMsgFindMode: + { + int8 mode; + if (message->FindInt8("mode", &mode) != B_OK) + break; + + if (fTextView->SetMode((find_mode)mode) == B_OK) { + // the "case sensitive" check box is only for ASCII mode + fCaseCheckBox->SetEnabled(mode == kAsciiMode); + } else { + // activate other item + fMenu->ItemAt(mode == kAsciiMode ? 1 : 0)->SetMarked(true); + beep(); + } + fTextView->MakeFocus(true); + break; + } + + case kMsgStartFind: + { + BMessage find(kMsgFind); + fTextView->GetData(find); + find.AddBool("case_sensitive", fCaseCheckBox->Value() != 0); + fTarget.SendMessage(&find); + + PostMessage(B_QUIT_REQUESTED); + break; + } + + default: + BWindow::MessageReceived(message); + } +} + + +bool +FindWindow::QuitRequested() +{ + be_app_messenger.SendMessage(kMsgFindWindowClosed); + return true; +} + + +void +FindWindow::SetTarget(BMessenger &target) +{ + fTarget = target; +} + diff --git a/src/apps/diskprobe/FindWindow.h b/src/apps/diskprobe/FindWindow.h new file mode 100644 index 0000000000..0a99e0c3bf --- /dev/null +++ b/src/apps/diskprobe/FindWindow.h @@ -0,0 +1,34 @@ +/* +** Copyright 2004, Axel Dörfler, axeld@pinc-software.de. All rights reserved. +** Distributed under the terms of the OpenBeOS License. +*/ +#ifndef FIND_WINDOW_H +#define FIND_WINDOW_H + + +#include +#include + +class FindTextView; +class BCheckBox; + + +class FindWindow : public BWindow { + public: + FindWindow(BRect rect, BMessenger &target); + virtual ~FindWindow(); + + virtual void WindowActivated(bool active); + virtual void MessageReceived(BMessage *message); + virtual bool QuitRequested(); + + void SetTarget(BMessenger &target); + + private: + BMessenger fTarget; + FindTextView *fTextView; + BCheckBox *fCaseCheckBox; + BMenu *fMenu; +}; + +#endif /* FIND_WINDOW_H */ diff --git a/src/apps/diskprobe/Jamfile b/src/apps/diskprobe/Jamfile index 73c6606183..fe993b4b22 100644 --- a/src/apps/diskprobe/Jamfile +++ b/src/apps/diskprobe/Jamfile @@ -14,6 +14,7 @@ App DiskProbe : AttributeEditors.cpp ProbeView.cpp OpenWindow.cpp + FindWindow.cpp ; LinkSharedOSLibs DiskProbe : be tracker translation ; diff --git a/src/apps/diskprobe/ProbeView.cpp b/src/apps/diskprobe/ProbeView.cpp index 07b96f0c1d..538a2b3132 100644 --- a/src/apps/diskprobe/ProbeView.cpp +++ b/src/apps/diskprobe/ProbeView.cpp @@ -55,8 +55,6 @@ static const uint32 kMsgAddBookmark = 'bmrk'; static const uint32 kMsgPrint = 'prnt'; static const uint32 kMsgPageSetup = 'pgsp'; -static const uint32 kMsgFind = 'find'; -static const uint32 kMsgFindWindow = 'fndw'; static const uint32 kMsgStopFind = 'sfnd'; @@ -970,7 +968,7 @@ EditorLooper::Find(off_t startAt, const uint8 *data, size_t dataSize, BMessenger // If the user had to wait more than 8 seconds for the result, // we are trying to please him with a requester... (new BAlert("DiskProbe request", - "Could not find pattern", "Ok", NULL, NULL, + "Could not find search string.", "Ok", NULL, NULL, B_WIDTH_AS_USUAL, B_WARNING_ALERT))->Go(NULL); } else beep(); @@ -1194,7 +1192,8 @@ ProbeView::AttachedToWindow() menu->AddItem(item = new BMenuItem("Select All", new BMessage(B_SELECT_ALL), 'A', B_COMMAND_KEY)); item->SetTarget(fDataView); menu->AddSeparatorItem(); - menu->AddItem(item = new BMenuItem("Find" B_UTF8_ELLIPSIS, new BMessage(kMsgFindWindow), 'F', B_COMMAND_KEY)); + menu->AddItem(item = new BMenuItem("Find" B_UTF8_ELLIPSIS, new BMessage(kMsgOpenFindWindow), + 'F', B_COMMAND_KEY)); item->SetTarget(this); menu->AddItem(fFindAgainMenuItem = new BMenuItem("Find Again", new BMessage(kMsgFind), 'G', B_COMMAND_KEY)); @@ -1335,8 +1334,15 @@ ProbeView::AllAttached() void ProbeView::WindowActivated(bool active) { - if (active) - fDataView->MakeFocus(true); + if (!active) + return; + + fDataView->MakeFocus(true); + + // set this view as the current find panel's target + BMessage target(kMsgFindTarget); + target.AddMessenger("target", this); + be_app_messenger.SendMessage(&target); } @@ -1662,14 +1668,15 @@ ProbeView::MessageReceived(BMessage *message) PageSetup(); break; - case kMsgFindWindow: + case kMsgOpenFindWindow: { fEditorLooper->QuitFind(); - // ToDo: open find window - message->AddData("data", B_RAW_TYPE, "test", 4); - message->what = kMsgFind; - //break; + // set this view as the current find panel's target + BMessage find(kMsgOpenFindWindow); + find.AddMessenger("target", this); + be_app_messenger.SendMessage(&find); + break; } case kMsgFind: