2 * Copyright 2004-2015, Axel Dörfler, axeld@pinc-software.de.
3 * Distributed under the terms of the MIT License.
14 #include <Application.h>
21 #include <Clipboard.h>
22 #include <Directory.h>
24 #include <ExpressionParser.h>
27 #include <GroupLayout.h>
28 #include <GroupLayoutBuilder.h>
29 #include <GroupView.h>
33 #include <MessageQueue.h>
36 #include <NodeMonitor.h>
39 #include <ScrollView.h>
40 #include <StringView.h>
43 #include <TextControl.h>
48 #include "DiskProbe.h"
49 #include "TypeEditors.h"
53 # define DRAW_SLIDER_BAR
54 // if this is defined, the standard slider bar is replaced with
55 // one that looks exactly like the one in the original DiskProbe
56 // (even in Dano/Zeta)
59 #undef B_TRANSLATION_CONTEXT
60 #define B_TRANSLATION_CONTEXT "ProbeView"
62 static const uint32 kMsgSliderUpdate
= 'slup';
63 static const uint32 kMsgPositionUpdate
= 'poup';
64 static const uint32 kMsgLastPosition
= 'lpos';
65 static const uint32 kMsgFontSize
= 'fnts';
66 static const uint32 kMsgBlockSize
= 'blks';
67 static const uint32 kMsgAddBookmark
= 'bmrk';
68 static const uint32 kMsgPrint
= 'prnt';
69 static const uint32 kMsgPageSetup
= 'pgsp';
70 static const uint32 kMsgViewAs
= 'vwas';
72 static const uint32 kMsgStopFind
= 'sfnd';
75 class IconView
: public BView
{
77 IconView(const entry_ref
*ref
, bool isDevice
);
80 virtual void AttachedToWindow();
81 virtual void Draw(BRect updateRect
);
92 class PositionSlider
: public BSlider
{
94 PositionSlider(const char *name
, BMessage
*message
, off_t size
,
96 virtual ~PositionSlider();
98 #ifdef DRAW_SLIDER_BAR
99 virtual void DrawBar();
102 off_t
Position() const;
103 off_t
Size() const { return fSize
; }
104 uint32
BlockSize() const { return fBlockSize
; }
106 virtual void SetPosition(float position
);
107 void SetPosition(off_t position
);
108 void SetSize(off_t size
);
109 void SetBlockSize(uint32 blockSize
);
114 static const int32 kMaxSliderLimit
= 0x7fffff80;
115 // this is the maximum value that BSlider seem to work with fine
122 class HeaderView
: public BGridView
, public BInvoker
{
124 HeaderView(const entry_ref
*ref
, DataEditor
&editor
);
125 virtual ~HeaderView();
127 virtual void AttachedToWindow();
128 virtual void DetachedFromWindow();
129 virtual void MessageReceived(BMessage
*message
);
131 base_type
Base() const { return fBase
; }
132 void SetBase(base_type
);
134 off_t
CursorOffset() const { return fPosition
% fBlockSize
; }
135 off_t
Position() const { return fPosition
; }
136 uint32
BlockSize() const { return fBlockSize
; }
137 void SetTo(off_t position
, uint32 blockSize
);
142 void FormatValue(char *buffer
, size_t bufferSize
, off_t value
);
143 void UpdatePositionViews(bool all
= true);
144 void UpdateOffsetViews(bool all
= true);
145 void UpdateFileSizeView();
148 const char *fAttribute
;
155 BTextControl
*fTypeControl
;
156 BTextControl
*fPositionControl
;
157 BStringView
*fPathView
;
158 BStringView
*fSizeView
;
159 BTextControl
*fOffsetControl
;
160 BTextControl
*fFileOffsetControl
;
161 PositionSlider
*fPositionSlider
;
163 BButton
*fStopButton
;
167 class TypeMenuItem
: public BMenuItem
{
169 TypeMenuItem(const char *name
, const char *type
, BMessage
*message
);
171 virtual void GetContentSize(float *_width
, float *_height
);
172 virtual void DrawContent();
179 class EditorLooper
: public BLooper
{
181 EditorLooper(const char *name
, DataEditor
&editor
, BMessenger messenger
);
182 virtual ~EditorLooper();
184 virtual void MessageReceived(BMessage
*message
);
186 bool FindIsRunning() const { return !fQuitFind
; }
187 void Find(off_t startAt
, const uint8
*data
, size_t dataSize
,
188 bool caseInsensitive
, BMessenger progressMonitor
);
193 BMessenger fMessenger
;
194 volatile bool fQuitFind
;
198 class TypeView
: public BView
{
200 TypeView(BRect rect
, const char* name
, int32 index
,
201 DataEditor
& editor
, int32 resizingMode
);
204 virtual void FrameResized(float width
, float height
);
207 BView
* fTypeEditorView
;
211 // #pragma mark - utility functions
215 get_type_string(char *buffer
, size_t bufferSize
, type_code type
)
217 for (int32 i
= 0; i
< 4; i
++) {
218 buffer
[i
] = type
>> (24 - 8 * i
);
219 if (buffer
[i
] < ' ' || buffer
[i
] == 0x7f) {
220 snprintf(buffer
, bufferSize
, "0x%04" B_PRIx32
, type
);
228 // #pragma mark - IconView
231 IconView::IconView(const entry_ref
*ref
, bool isDevice
)
232 : BView(NULL
, B_WILL_DRAW
),
238 SetExplicitSize(BSize(32, 32));
242 IconView::~IconView()
249 IconView::AttachedToWindow()
251 if (Parent() != NULL
)
252 SetViewColor(Parent()->ViewColor());
254 SetViewUIColor(B_PANEL_BACKGROUND_COLOR
);
259 IconView::Draw(BRect updateRect
)
264 SetDrawingMode(B_OP_ALPHA
);
265 DrawBitmap(fBitmap
, updateRect
, updateRect
);
266 SetDrawingMode(B_OP_COPY
);
271 IconView::UpdateIcon()
274 #ifdef HAIKU_TARGET_PLATFORM_HAIKU
275 fBitmap
= new BBitmap(BRect(0, 0, 31, 31), B_RGBA32
);
277 fBitmap
= new BBitmap(BRect(0, 0, 31, 31), B_CMAP8
);
280 if (fBitmap
!= NULL
) {
281 status_t status
= B_ERROR
;
286 status
= get_device_icon(path
.Path(), fBitmap
, B_LARGE_ICON
);
288 status
= get_device_icon(path
.Path(), fBitmap
->Bits(), B_LARGE_ICON
);
291 status
= BNodeInfo::GetTrackerIcon(&fRef
, fBitmap
);
293 if (status
!= B_OK
) {
294 // Try to get generic icon
295 BMimeType
type(B_FILE_MIME_TYPE
);
296 status
= type
.GetIcon(fBitmap
, B_LARGE_ICON
);
299 if (status
!= B_OK
) {
309 // #pragma mark - PositionSlider
312 PositionSlider::PositionSlider(const char *name
, BMessage
*message
,
313 off_t size
, uint32 blockSize
)
314 : BSlider(name
, NULL
, message
, 0, kMaxSliderLimit
, B_HORIZONTAL
,
317 fBlockSize(blockSize
)
321 #ifndef DRAW_SLIDER_BAR
322 rgb_color color
= ui_color(B_CONTROL_HIGHLIGHT_COLOR
);
323 UseFillColor(true, &color
);
328 PositionSlider::~PositionSlider()
333 #ifdef DRAW_SLIDER_BAR
335 PositionSlider::DrawBar()
337 BView
*view
= OffscreenView();
339 BRect barFrame
= BarFrame();
340 BRect frame
= barFrame
.InsetByCopy(1, 1);
343 frame
.right
= ThumbFrame().left
+ ThumbFrame().Width() / 2;
344 #ifdef HAIKU_TARGET_PLATFORM_BEOS
346 view
->SetHighColor(102, 152, 203);
348 view
->SetHighColor(92, 102, 160);
350 view
->SetHighColor(IsEnabled() ? ui_color(B_CONTROL_HIGHLIGHT_COLOR
)
351 : tint_color(ui_color(B_CONTROL_HIGHLIGHT_COLOR
), B_DARKEN_1_TINT
));
353 view
->FillRect(frame
);
355 frame
.left
= frame
.right
+ 1;
356 frame
.right
= barFrame
.right
- 1;
357 view
->SetHighColor(tint_color(ViewColor(), IsEnabled() ? B_DARKEN_1_TINT
: B_LIGHTEN_1_TINT
));
358 view
->FillRect(frame
);
360 rgb_color cornerColor
= tint_color(ViewColor(), B_DARKEN_1_TINT
);
361 rgb_color darkColor
= tint_color(ViewColor(), B_DARKEN_3_TINT
);
362 #ifdef HAIKU_TARGET_PLATFORM_BEOS
363 rgb_color shineColor
= {255, 255, 255};
364 rgb_color shadowColor
= {0, 0, 0};
366 rgb_color shineColor
= ui_color(B_SHINE_COLOR
);
367 rgb_color shadowColor
= ui_color(B_SHADOW_COLOR
);
370 darkColor
= tint_color(ViewColor(), B_DARKEN_1_TINT
);
371 shineColor
= tint_color(shineColor
, B_DARKEN_2_TINT
);
372 shadowColor
= tint_color(shadowColor
, B_LIGHTEN_2_TINT
);
375 view
->BeginLineArray(9);
378 view
->AddLine(barFrame
.LeftTop(), barFrame
.LeftTop(), cornerColor
);
379 view
->AddLine(barFrame
.LeftBottom(), barFrame
.LeftBottom(), cornerColor
);
380 view
->AddLine(barFrame
.RightTop(), barFrame
.RightTop(), cornerColor
);
383 view
->AddLine(BPoint(barFrame
.left
, barFrame
.top
+ 1),
384 BPoint(barFrame
.left
, barFrame
.bottom
- 1), darkColor
);
385 view
->AddLine(BPoint(barFrame
.right
, barFrame
.top
+ 1),
386 BPoint(barFrame
.right
, barFrame
.bottom
), shineColor
);
390 view
->AddLine(barFrame
.LeftTop(), barFrame
.RightTop(), darkColor
);
391 view
->AddLine(barFrame
.LeftBottom(), barFrame
.RightBottom(), shineColor
);
395 view
->AddLine(barFrame
.LeftTop(), barFrame
.RightTop(), shadowColor
);
396 view
->AddLine(BPoint(barFrame
.left
, barFrame
.top
+ 1),
397 BPoint(barFrame
.left
, barFrame
.bottom
- 1), shadowColor
);
399 view
->EndLineArray();
401 #endif // DRAW_SLIDER_BAR
405 PositionSlider::Reset()
407 SetKeyIncrementValue(int32(1.0 * kMaxSliderLimit
/ ((fSize
- 1) / fBlockSize
) + 0.5));
408 SetEnabled(fSize
> fBlockSize
);
413 PositionSlider::Position() const
416 // Note: this code is far from being perfect: depending on the file size, it has
417 // a maxium granularity that might be less than the actual block size demands...
418 // The only way to work around this that I can think of, is to replace the slider
419 // class completely with one that understands off_t values.
420 // For example, with a block size of 512 bytes, it should be good enough for about
421 // 1024 GB - and that's not really that far away these days.
423 return (off_t(1.0 * (fSize
- 1) * Value() / kMaxSliderLimit
+ 0.5) / fBlockSize
) * fBlockSize
;
428 PositionSlider::SetPosition(float position
)
430 BSlider::SetPosition(position
);
435 PositionSlider::SetPosition(off_t position
)
437 position
/= fBlockSize
;
438 SetValue(int32(1.0 * kMaxSliderLimit
* position
/ ((fSize
- 1) / fBlockSize
) + 0.5));
443 PositionSlider::SetSize(off_t size
)
448 off_t position
= Position();
449 if (position
>= size
)
454 SetPosition(position
);
459 PositionSlider::SetBlockSize(uint32 blockSize
)
461 if (blockSize
== fBlockSize
)
464 off_t position
= Position();
465 fBlockSize
= blockSize
;
467 SetPosition(position
);
471 // #pragma mark - HeaderView
474 HeaderView::HeaderView(const entry_ref
*ref
, DataEditor
&editor
)
475 : BGridView("probeHeader", B_USE_SMALL_SPACING
, B_USE_SMALL_SPACING
),
476 fAttribute(editor
.Attribute()),
477 fFileSize(editor
.FileSize()),
478 fBlockSize(editor
.BlockSize()),
483 SetViewUIColor(B_PANEL_BACKGROUND_COLOR
);
484 GridLayout()->SetInsets(B_USE_WINDOW_SPACING
, B_USE_WINDOW_SPACING
,
485 B_USE_WINDOW_SPACING
, B_USE_DEFAULT_SPACING
);
487 fIconView
= new IconView(ref
, editor
.IsDevice());
488 GridLayout()->AddView(fIconView
, 0, 0, 1, 2);
490 BGroupView
* line
= new BGroupView(B_HORIZONTAL
);
491 GridLayout()->AddView(line
, 1, 0);
493 BFont boldFont
= *be_bold_font
;
494 BFont plainFont
= *be_plain_font
;
495 boldFont
.SetSize(plainFont
.Size() * 0.83);
496 plainFont
.SetSize(plainFont
.Size() * 0.83);
498 BStringView
*stringView
= new BStringView(
499 B_EMPTY_STRING
, editor
.IsAttribute()
500 ? B_TRANSLATE("Attribute: ") : editor
.IsDevice()
501 ? B_TRANSLATE("Device: ") : B_TRANSLATE("File: "));
502 stringView
->SetFont(&boldFont
);
503 line
->AddChild(stringView
);
506 BString string
= path
.Path();
507 if (fAttribute
!= NULL
) {
508 string
.Prepend(" (");
509 string
.Prepend(fAttribute
);
512 fPathView
= new BStringView(B_EMPTY_STRING
, string
.String());
513 fPathView
->SetFont(&plainFont
);
514 line
->AddChild(fPathView
);
516 if (editor
.IsAttribute()) {
517 stringView
= new BStringView(B_EMPTY_STRING
,
518 B_TRANSLATE("Attribute type: "));
519 stringView
->SetFont(&boldFont
);
520 line
->AddChild(stringView
);
523 get_type_string(buffer
, sizeof(buffer
), editor
.Type());
524 fTypeControl
= new BTextControl(B_EMPTY_STRING
, NULL
, buffer
,
525 new BMessage(kMsgPositionUpdate
));
526 fTypeControl
->SetFont(&plainFont
);
527 fTypeControl
->TextView()->SetFontAndColor(&plainFont
);
528 fTypeControl
->SetEnabled(false);
530 line
->AddChild(fTypeControl
);
535 fStopButton
= new BButton(B_EMPTY_STRING
,
536 B_TRANSLATE("Stop"), new BMessage(kMsgStopFind
));
537 fStopButton
->SetFont(&plainFont
);
539 line
->AddChild(fStopButton
);
541 BGroupLayoutBuilder(line
).AddGlue();
543 line
= new BGroupView(B_HORIZONTAL
, B_USE_SMALL_SPACING
);
544 GridLayout()->AddView(line
, 1, 1);
546 stringView
= new BStringView(B_EMPTY_STRING
, B_TRANSLATE("Block: "));
547 stringView
->SetFont(&boldFont
);
548 line
->AddChild(stringView
);
550 BMessage
* msg
= new BMessage(kMsgPositionUpdate
);
551 msg
->AddBool("fPositionControl", true);
552 // BTextControl oddities
553 fPositionControl
= new BTextControl(B_EMPTY_STRING
, NULL
, "0x0", msg
);
554 fPositionControl
->SetDivider(0.0);
555 fPositionControl
->SetFont(&plainFont
);
556 fPositionControl
->TextView()->SetFontAndColor(&plainFont
);
557 fPositionControl
->SetAlignment(B_ALIGN_LEFT
, B_ALIGN_LEFT
);
558 line
->AddChild(fPositionControl
);
560 fSizeView
= new BStringView(B_EMPTY_STRING
, B_TRANSLATE_COMMENT("of "
561 "0x0", "This is a part of 'Block 0xXXXX of 0x0026' message. In "
562 "languages without 'of' structure it can be replaced simply "
564 fSizeView
->SetFont(&plainFont
);
565 line
->AddChild(fSizeView
);
566 UpdateFileSizeView();
568 stringView
= new BStringView(B_EMPTY_STRING
, B_TRANSLATE("Offset: "));
569 stringView
->SetFont(&boldFont
);
570 line
->AddChild(stringView
);
572 msg
= new BMessage(kMsgPositionUpdate
);
573 msg
->AddBool("fOffsetControl", false);
574 fOffsetControl
= new BTextControl(B_EMPTY_STRING
, NULL
, "0x0", msg
);
575 fOffsetControl
->SetDivider(0.0);
576 fOffsetControl
->SetFont(&plainFont
);
577 fOffsetControl
->TextView()->SetFontAndColor(&plainFont
);
578 fOffsetControl
->SetAlignment(B_ALIGN_LEFT
, B_ALIGN_LEFT
);
579 line
->AddChild(fOffsetControl
);
580 UpdateOffsetViews(false);
582 stringView
= new BStringView(B_EMPTY_STRING
, editor
.IsAttribute()
583 ? B_TRANSLATE("Attribute offset: ") : editor
.IsDevice()
584 ? B_TRANSLATE("Device offset: ") : B_TRANSLATE("File offset: "));
585 stringView
->SetFont(&boldFont
);
586 line
->AddChild(stringView
);
588 msg
= new BMessage(kMsgPositionUpdate
);
589 msg
->AddBool("fFileOffsetControl", false);
590 fFileOffsetControl
= new BTextControl(B_EMPTY_STRING
, NULL
, "0x0", msg
);
591 fFileOffsetControl
->SetDivider(0.0);
592 fFileOffsetControl
->SetFont(&plainFont
);
593 fFileOffsetControl
->TextView()->SetFontAndColor(&plainFont
);
594 fFileOffsetControl
->SetAlignment(B_ALIGN_LEFT
, B_ALIGN_LEFT
);
595 line
->AddChild(fFileOffsetControl
);
597 BGroupLayoutBuilder(line
).AddGlue();
599 fPositionSlider
= new PositionSlider("slider",
600 new BMessage(kMsgSliderUpdate
), editor
.FileSize(), editor
.BlockSize());
601 fPositionSlider
->SetModificationMessage(new BMessage(kMsgSliderUpdate
));
602 fPositionSlider
->SetBarThickness(8);
603 GridLayout()->AddView(fPositionSlider
, 0, 2, 2, 1);
607 HeaderView::~HeaderView()
613 HeaderView::AttachedToWindow()
617 fStopButton
->SetTarget(Parent());
618 fPositionControl
->SetTarget(this);
619 fOffsetControl
->SetTarget(this);
620 fFileOffsetControl
->SetTarget(this);
621 fPositionSlider
->SetTarget(this);
624 Window()->AddShortcut(B_HOME
, B_COMMAND_KEY
,
625 message
= new BMessage(kMsgPositionUpdate
), this);
626 message
->AddInt64("block", 0);
627 Window()->AddShortcut(B_END
, B_COMMAND_KEY
,
628 message
= new BMessage(kMsgPositionUpdate
), this);
629 message
->AddInt64("block", -1);
630 Window()->AddShortcut(B_PAGE_UP
, B_COMMAND_KEY
,
631 message
= new BMessage(kMsgPositionUpdate
), this);
632 message
->AddInt32("delta", -1);
633 Window()->AddShortcut(B_PAGE_DOWN
, B_COMMAND_KEY
,
634 message
= new BMessage(kMsgPositionUpdate
), this);
635 message
->AddInt32("delta", 1);
640 HeaderView::DetachedFromWindow()
642 Window()->RemoveShortcut(B_HOME
, B_COMMAND_KEY
);
643 Window()->RemoveShortcut(B_END
, B_COMMAND_KEY
);
644 Window()->RemoveShortcut(B_PAGE_UP
, B_COMMAND_KEY
);
645 Window()->RemoveShortcut(B_PAGE_DOWN
, B_COMMAND_KEY
);
650 HeaderView::UpdateIcon()
652 fIconView
->UpdateIcon();
657 HeaderView::FormatValue(char *buffer
, size_t bufferSize
, off_t value
)
659 snprintf(buffer
, bufferSize
, fBase
== kHexBase
? "0x%" B_PRIxOFF
: "%"
665 HeaderView::UpdatePositionViews(bool all
)
668 FormatValue(buffer
, sizeof(buffer
), fPosition
/ fBlockSize
);
669 fPositionControl
->SetText(buffer
);
672 FormatValue(buffer
, sizeof(buffer
), fPosition
);
673 fFileOffsetControl
->SetText(buffer
);
679 HeaderView::UpdateOffsetViews(bool all
)
682 FormatValue(buffer
, sizeof(buffer
), fPosition
% fBlockSize
);
683 fOffsetControl
->SetText(buffer
);
686 FormatValue(buffer
, sizeof(buffer
), fPosition
);
687 fFileOffsetControl
->SetText(buffer
);
693 HeaderView::UpdateFileSizeView()
695 BString
string(B_TRANSLATE("of "));
697 FormatValue(buffer
, sizeof(buffer
),
698 (fFileSize
+ fBlockSize
- 1) / fBlockSize
);
701 fSizeView
->SetText(string
.String());
706 HeaderView::SetBase(base_type type
)
713 UpdatePositionViews();
714 UpdateOffsetViews(false);
715 UpdateFileSizeView();
720 HeaderView::SetTo(off_t position
, uint32 blockSize
)
722 fPosition
= position
;
723 fLastPosition
= (fLastPosition
/ fBlockSize
) * blockSize
;
724 fBlockSize
= blockSize
;
726 fPositionSlider
->SetBlockSize(blockSize
);
727 UpdatePositionViews();
728 UpdateOffsetViews(false);
729 UpdateFileSizeView();
734 HeaderView::NotifyTarget()
736 BMessage
update(kMsgPositionUpdate
);
737 update
.AddInt64("position", fPosition
);
738 Messenger().SendMessage(&update
);
743 HeaderView::MessageReceived(BMessage
*message
)
745 switch (message
->what
) {
746 case B_OBSERVER_NOTICE_CHANGE
: {
748 if (message
->FindInt32(B_OBSERVE_WHAT_CHANGE
, &what
) != B_OK
)
752 case kDataViewCursorPosition
:
754 if (message
->FindInt64("position", &offset
) == B_OK
) {
755 fPosition
= (fPosition
/ fBlockSize
) * fBlockSize
764 case kMsgSliderUpdate
:
766 // First, make sure we're only considering the most
767 // up-to-date message in the queue (which might not
769 // If there is another message of this type in the
770 // queue, we're just ignoring the current message.
772 if (Looper()->MessageQueue()->FindMessage(kMsgSliderUpdate
, 0)
776 // if nothing has changed, we can ignore this message as well
777 if (fPosition
== fPositionSlider
->Position())
780 fLastPosition
= fPosition
;
781 fPosition
= fPositionSlider
->Position();
783 // update position text control
784 UpdatePositionViews();
791 case kMsgDataEditorFindProgress
:
794 if (message
->FindBool("running", &state
) == B_OK
795 && fFileSize
> fBlockSize
) {
796 fPositionSlider
->SetEnabled(!state
);
805 if (message
->FindInt64("position", &position
) != B_OK
)
808 fPosition
= (position
/ fBlockSize
) * fBlockSize
;
809 // round to block size
812 UpdatePositionViews(false);
813 fPositionSlider
->SetPosition(fPosition
);
817 case kMsgPositionUpdate
:
819 off_t lastPosition
= fPosition
;
824 if (message
->FindInt64("position", &position
) == B_OK
)
825 fPosition
= position
;
826 else if (message
->FindInt64("block", &position
) == B_OK
) {
828 position
+= (fFileSize
- 1) / fBlockSize
+ 1;
829 fPosition
= position
* fBlockSize
;
830 } else if (message
->FindInt32("delta", &delta
) == B_OK
) {
831 fPosition
+= delta
* off_t(fBlockSize
);
834 ExpressionParser parser
;
835 parser
.SetSupportHexInput(true);
836 if (message
->FindBool("fPositionControl", &round
)
838 fPosition
= parser
.EvaluateToInt64(
839 fPositionControl
->Text()) * fBlockSize
;
840 } else if (message
->FindBool("fOffsetControl", &round
)
842 fPosition
= (fPosition
/ fBlockSize
) * fBlockSize
+
843 parser
.EvaluateToInt64(fOffsetControl
->Text());
844 } else if (message
->FindBool("fFileOffsetControl", &round
)
846 fPosition
= parser
.EvaluateToInt64(
847 fFileOffsetControl
->Text());
855 fLastPosition
= lastPosition
;
858 fPosition
= (fPosition
/ fBlockSize
) * fBlockSize
;
859 // round to block size
863 else if (fPosition
> ((fFileSize
- 1) / fBlockSize
) * fBlockSize
)
864 fPosition
= ((fFileSize
- 1) / fBlockSize
) * fBlockSize
;
867 UpdatePositionViews();
868 fPositionSlider
->SetPosition(fPosition
);
875 case kMsgLastPosition
:
877 fPosition
= fLastPosition
;
878 fLastPosition
= fPositionSlider
->Position();
881 UpdatePositionViews();
882 fPositionSlider
->SetPosition(fPosition
);
892 if (message
->FindInt32("base", &type
) != B_OK
)
895 SetBase((base_type
)type
);
900 BView::MessageReceived(message
);
905 // #pragma mark - TypeMenuItem
908 /*! The TypeMenuItem is a BMenuItem that displays a type string at its
910 It is used to display the attribute and type in the attributes menu.
911 It does not mix nicely with short cuts.
913 TypeMenuItem::TypeMenuItem(const char *name
, const char *type
,
915 : BMenuItem(name
, message
),
922 TypeMenuItem::GetContentSize(float *_width
, float *_height
)
924 BMenuItem::GetContentSize(_width
, _height
);
927 *_width
+= Menu()->StringWidth(fType
.String());
932 TypeMenuItem::DrawContent()
935 BMenuItem::DrawContent();
937 font_height fontHeight
;
938 Menu()->GetFontHeight(&fontHeight
);
941 BPoint point
= ContentLocation();
942 point
.x
= Frame().right
- 4 - Menu()->StringWidth(fType
.String());
943 point
.y
+= fontHeight
.ascent
;
945 #ifdef HAIKU_TARGET_PLATFORM_BEOS
946 Menu()->SetDrawingMode(B_OP_ALPHA
);
949 Menu()->DrawString(fType
.String(), point
);
953 // #pragma mark - EditorLooper
956 /*! The purpose of this looper is to off-load the editor data loading from
957 the main window looper.
959 It will listen to the offset changes of the editor, let him update its
960 data, and will then synchronously notify the target.
961 That way, simple offset changes will not stop the main looper from
962 operating. Therefore, all offset updates for the editor will go through
964 Also, it will run the find action in the editor.
966 EditorLooper::EditorLooper(const char *name
, DataEditor
&editor
,
973 fEditor
.StartWatching(this);
977 EditorLooper::~EditorLooper()
979 fEditor
.StopWatching(this);
984 EditorLooper::MessageReceived(BMessage
*message
)
986 switch (message
->what
) {
987 case kMsgPositionUpdate
:
989 // First, make sure we're only considering the most
990 // up-to-date message in the queue (which might not
992 // If there is another message of this type in the
993 // queue, we're just ignoring the current message.
995 if (Looper()->MessageQueue()->FindMessage(kMsgPositionUpdate
, 0) != NULL
)
999 if (message
->FindInt64("position", &position
) == B_OK
) {
1000 BAutolock
locker(fEditor
);
1001 fEditor
.SetViewOffset(position
);
1003 BMessage
message(kMsgSetSelection
);
1004 message
.AddInt64("start", position
- fEditor
.ViewOffset());
1005 message
.AddInt64("end", position
- fEditor
.ViewOffset());
1006 fMessenger
.SendMessage(&message
);
1011 case kMsgDataEditorParameterChange
:
1013 bool updated
= false;
1015 if (fEditor
.Lock()) {
1016 fEditor
.UpdateIfNeeded(&updated
);
1022 fMessenger
.SendMessage(kMsgUpdateData
, &reply
);
1023 // We are doing a synchronously transfer, to prevent
1024 // that we're already locking the editor again when
1025 // our target wants to get the editor data.
1032 BMessenger progressMonitor
;
1033 message
->FindMessenger("progress_monitor", &progressMonitor
);
1036 message
->FindInt64("start", &startAt
);
1038 bool caseInsensitive
= !message
->FindBool("case_sensitive");
1042 if (message
->FindData("data", B_RAW_TYPE
, (const void **)&data
,
1044 Find(startAt
, data
, dataSize
, caseInsensitive
, progressMonitor
);
1048 BLooper::MessageReceived(message
);
1055 EditorLooper::Find(off_t startAt
, const uint8
*data
, size_t dataSize
,
1056 bool caseInsensitive
, BMessenger progressMonitor
)
1060 BAutolock
locker(fEditor
);
1062 bigtime_t startTime
= system_time();
1064 off_t foundAt
= fEditor
.Find(startAt
, data
, dataSize
, caseInsensitive
,
1065 true, progressMonitor
, &fQuitFind
);
1066 if (foundAt
>= B_OK
) {
1067 fEditor
.SetViewOffset(foundAt
);
1069 // select the part in our target
1070 BMessage
message(kMsgSetSelection
);
1071 message
.AddInt64("start", foundAt
- fEditor
.ViewOffset());
1072 message
.AddInt64("end", foundAt
+ dataSize
- 1 - fEditor
.ViewOffset());
1073 fMessenger
.SendMessage(&message
);
1074 } else if (foundAt
== B_ENTRY_NOT_FOUND
) {
1075 if (system_time() > startTime
+ 8000000LL) {
1076 // If the user had to wait more than 8 seconds for the result,
1077 // we are trying to please him with a requester...
1078 BAlert
* alert
= new BAlert(B_TRANSLATE("DiskProbe request"),
1079 B_TRANSLATE("Could not find search string."),
1080 B_TRANSLATE("OK"), NULL
, NULL
, B_WIDTH_AS_USUAL
,
1082 alert
->SetFlags(alert
->Flags() | B_CLOSE_ON_ESCAPE
);
1091 EditorLooper::QuitFind()
1094 // this will cleanly stop the find process
1098 // #pragma mark - TypeView
1101 TypeView::TypeView(BRect rect
, const char* name
, int32 index
,
1102 DataEditor
& editor
, int32 resizingMode
)
1103 : BView(rect
, name
, resizingMode
, B_FRAME_EVENTS
)
1105 SetViewUIColor(B_PANEL_BACKGROUND_COLOR
);
1107 fTypeEditorView
= GetTypeEditorAt(index
, Frame(), editor
);
1108 if (fTypeEditorView
== NULL
) {
1109 AddChild(new BStringView(Bounds(), B_TRANSLATE("Type editor"),
1110 B_TRANSLATE("Type editor not supported"), B_FOLLOW_NONE
));
1112 AddChild(fTypeEditorView
);
1114 if ((fTypeEditorView
->ResizingMode() & (B_FOLLOW_RIGHT
| B_FOLLOW_BOTTOM
))
1116 BRect rect
= Bounds();
1118 BRect frame
= fTypeEditorView
->Frame();
1119 rect
.left
= frame
.left
;
1120 rect
.top
= frame
.top
;
1121 if ((fTypeEditorView
->ResizingMode() & B_FOLLOW_RIGHT
) == 0)
1122 rect
.right
= frame
.right
;
1123 if ((fTypeEditorView
->ResizingMode() & B_FOLLOW_BOTTOM
) == 0)
1124 rect
.bottom
= frame
.bottom
;
1126 fTypeEditorView
->ResizeTo(rect
.Width(), rect
.Height());
1131 TypeView::~TypeView()
1137 TypeView::FrameResized(float width
, float height
)
1139 BRect rect
= Bounds();
1141 BPoint point
= fTypeEditorView
->Frame().LeftTop();
1142 if ((fTypeEditorView
->ResizingMode() & B_FOLLOW_RIGHT
) == 0)
1143 point
.x
= (rect
.Width() - fTypeEditorView
->Bounds().Width()) / 2;
1144 if ((fTypeEditorView
->ResizingMode() & B_FOLLOW_BOTTOM
) == 0)
1145 point
.y
= (rect
.Height() - fTypeEditorView
->Bounds().Height()) / 2;
1147 fTypeEditorView
->MoveTo(point
);
1151 // #pragma mark - ProbeView
1154 ProbeView::ProbeView(entry_ref
*ref
, const char *attribute
,
1155 const BMessage
*settings
)
1156 : BView("probeView", B_WILL_DRAW
),
1157 fPrintSettings(NULL
),
1161 BGroupLayout
* layout
= new BGroupLayout(B_VERTICAL
, 0);
1163 layout
->SetInsets(-1, -1, -1, -1);
1164 fEditor
.SetTo(*ref
, attribute
);
1166 int32 baseType
= kHexBase
;
1167 float fontSize
= 12.0f
;
1168 if (settings
!= NULL
) {
1169 settings
->FindInt32("base_type", &baseType
);
1170 settings
->FindFloat("font_size", &fontSize
);
1173 fHeaderView
= new HeaderView(&fEditor
.Ref(), fEditor
);
1174 fHeaderView
->SetBase((base_type
)baseType
);
1175 AddChild(fHeaderView
);
1177 fDataView
= new DataView(fEditor
);
1178 fDataView
->SetBase((base_type
)baseType
);
1179 fDataView
->SetFontSize(fontSize
);
1181 fScrollView
= new BScrollView("scroller", fDataView
, B_WILL_DRAW
, true,
1183 AddChild(fScrollView
);
1185 fDataView
->UpdateScroller();
1189 ProbeView::~ProbeView()
1195 ProbeView::DetachedFromWindow()
1197 fEditorLooper
->QuitFind();
1199 if (fEditorLooper
->Lock())
1200 fEditorLooper
->Quit();
1201 fEditorLooper
= NULL
;
1203 fEditor
.StopWatching(this);
1204 fDataView
->StopWatching(fHeaderView
, kDataViewCursorPosition
);
1205 fDataView
->StopWatching(this, kDataViewSelection
);
1206 fDataView
->StopWatching(this, kDataViewPreferredSize
);
1207 be_clipboard
->StopWatching(this);
1212 ProbeView::_UpdateAttributesMenu(BMenu
*menu
)
1214 // remove old contents
1216 for (int32 i
= menu
->CountItems(); i
-- > 0;) {
1217 delete menu
->RemoveItem(i
);
1220 // add new items (sorted)
1222 BNode
node(&fEditor
.AttributeRef());
1223 if (node
.InitCheck() == B_OK
) {
1224 char attribute
[B_ATTR_NAME_LENGTH
];
1227 while (node
.GetNextAttrName(attribute
) == B_OK
) {
1229 if (node
.GetAttrInfo(attribute
, &info
) != B_OK
)
1234 get_type_string(type
+ 1, sizeof(type
) - 2, info
.type
);
1237 // find where to insert
1239 for (i
= 0; i
< menu
->CountItems(); i
++) {
1240 if (strcasecmp(menu
->ItemAt(i
)->Label(), attribute
) > 0)
1244 BMessage
*message
= new BMessage(B_REFS_RECEIVED
);
1245 message
->AddRef("refs", &fEditor
.AttributeRef());
1246 message
->AddString("attributes", attribute
);
1248 menu
->AddItem(new TypeMenuItem(attribute
, type
, message
), i
);
1252 if (menu
->CountItems() == 0) {
1253 // if there are no attributes, add an item to the menu
1255 BMenuItem
*item
= new BMenuItem(B_TRANSLATE_COMMENT("none",
1256 "No attributes"), NULL
);
1257 item
->SetEnabled(false);
1258 menu
->AddItem(item
);
1261 menu
->SetTargetForItems(be_app
);
1266 ProbeView::AddSaveMenuItems(BMenu
* menu
, int32 index
)
1268 menu
->AddItem(fSaveMenuItem
= new BMenuItem(B_TRANSLATE("Save"),
1269 new BMessage(B_SAVE_REQUESTED
), 'S'), index
);
1270 fSaveMenuItem
->SetTarget(this);
1271 fSaveMenuItem
->SetEnabled(false);
1272 //menu->AddItem(new BMenuItem("Save As" B_UTF8_ELLIPSIS, NULL), index);
1277 ProbeView::AddPrintMenuItems(BMenu
* menu
, int32 index
)
1280 menu
->AddItem(item
= new BMenuItem(B_TRANSLATE("Page setup" B_UTF8_ELLIPSIS
),
1281 new BMessage(kMsgPageSetup
)), index
++);
1282 item
->SetTarget(this);
1283 menu
->AddItem(item
= new BMenuItem(B_TRANSLATE("Print" B_UTF8_ELLIPSIS
),
1284 new BMessage(kMsgPrint
), 'P'), index
++);
1285 item
->SetTarget(this);
1290 ProbeView::AddViewAsMenuItems()
1293 BMenuBar
* bar
= Window()->KeyMenuBar();
1297 BMenuItem
* item
= bar
->FindItem(B_TRANSLATE("View"));
1300 menu
= item
->Submenu();
1302 menu
= bar
->SubmenuAt(bar
->CountItems() - 1);
1307 menu
->AddSeparatorItem();
1309 BMenu
* subMenu
= new BMenu(B_TRANSLATE("View As"));
1310 subMenu
->SetRadioMode(true);
1312 BMessage
* message
= new BMessage(kMsgViewAs
);
1313 subMenu
->AddItem(item
= new BMenuItem(B_TRANSLATE("Raw"), message
));
1314 item
->SetMarked(true);
1317 for (int32 i
= 0; GetNthTypeEditor(i
, &name
) == B_OK
; i
++) {
1318 message
= new BMessage(kMsgViewAs
);
1319 message
->AddInt32("editor index", i
);
1320 subMenu
->AddItem(new BMenuItem(name
, message
));
1323 subMenu
->SetTargetForItems(this);
1324 menu
->AddItem(new BMenuItem(subMenu
));
1330 ProbeView::AttachedToWindow()
1332 BView::AttachedToWindow();
1334 fEditorLooper
= new EditorLooper(fEditor
.Ref().name
, fEditor
,
1335 BMessenger(fDataView
));
1336 fEditorLooper
->Run();
1338 fEditor
.StartWatching(this);
1339 fDataView
->StartWatching(fHeaderView
, kDataViewCursorPosition
);
1340 fDataView
->StartWatching(this, kDataViewSelection
);
1341 fDataView
->StartWatching(this, kDataViewPreferredSize
);
1342 be_clipboard
->StartWatching(this);
1344 // Add menu to window
1346 BMenuBar
*bar
= Window()->KeyMenuBar();
1348 // there is none? Well, but we really want to have one
1349 bar
= new BMenuBar("");
1350 Window()->AddChild(bar
);
1352 BMenu
*menu
= new BMenu(fEditor
.IsAttribute()
1353 ? B_TRANSLATE("Attribute") : fEditor
.IsDevice() ? B_TRANSLATE("Device") : B_TRANSLATE("File"));
1354 AddSaveMenuItems(menu
, 0);
1355 menu
->AddSeparatorItem();
1356 AddPrintMenuItems(menu
, menu
->CountItems());
1357 menu
->AddSeparatorItem();
1359 menu
->AddItem(new BMenuItem(B_TRANSLATE("Close"), new BMessage(B_CLOSE_REQUESTED
),
1366 BMenu
*menu
= new BMenu(B_TRANSLATE("Edit"));
1368 menu
->AddItem(fUndoMenuItem
= new BMenuItem(B_TRANSLATE("Undo"), new BMessage(B_UNDO
),
1370 fUndoMenuItem
->SetEnabled(fEditor
.CanUndo());
1371 fUndoMenuItem
->SetTarget(fDataView
);
1372 menu
->AddItem(fRedoMenuItem
= new BMenuItem(B_TRANSLATE("Redo"), new BMessage(B_REDO
),
1374 fRedoMenuItem
->SetEnabled(fEditor
.CanRedo());
1375 fRedoMenuItem
->SetTarget(fDataView
);
1376 menu
->AddSeparatorItem();
1377 menu
->AddItem(item
= new BMenuItem(B_TRANSLATE("Copy"), new BMessage(B_COPY
), 'C'));
1378 item
->SetTarget(NULL
, Window());
1379 menu
->AddItem(fPasteMenuItem
= new BMenuItem(B_TRANSLATE("Paste"), new BMessage(B_PASTE
),
1381 fPasteMenuItem
->SetTarget(NULL
, Window());
1383 menu
->AddItem(item
= new BMenuItem(B_TRANSLATE("Select all"), new BMessage(B_SELECT_ALL
),
1385 item
->SetTarget(NULL
, Window());
1386 menu
->AddSeparatorItem();
1387 menu
->AddItem(item
= new BMenuItem(B_TRANSLATE("Find" B_UTF8_ELLIPSIS
),
1388 new BMessage(kMsgOpenFindWindow
), 'F'));
1389 item
->SetTarget(this);
1390 menu
->AddItem(fFindAgainMenuItem
= new BMenuItem(B_TRANSLATE("Find again"),
1391 new BMessage(kMsgFind
), 'G'));
1392 fFindAgainMenuItem
->SetEnabled(false);
1393 fFindAgainMenuItem
->SetTarget(this);
1398 menu
= new BMenu(B_TRANSLATE("Block"));
1399 BMessage
*message
= new BMessage(kMsgPositionUpdate
);
1400 message
->AddInt32("delta", 1);
1401 menu
->AddItem(item
= new BMenuItem(B_TRANSLATE("Next"), message
, B_RIGHT_ARROW
));
1402 item
->SetTarget(fHeaderView
);
1403 message
= new BMessage(kMsgPositionUpdate
);
1404 message
->AddInt32("delta", -1);
1405 menu
->AddItem(item
= new BMenuItem(B_TRANSLATE("Previous"), message
, B_LEFT_ARROW
));
1406 item
->SetTarget(fHeaderView
);
1407 menu
->AddItem(item
= new BMenuItem(B_TRANSLATE("Back"), new BMessage(kMsgLastPosition
),
1409 item
->SetTarget(fHeaderView
);
1411 BMenu
*subMenu
= new BMenu(B_TRANSLATE("Selection"));
1412 message
= new BMessage(kMsgPositionUpdate
);
1413 message
->AddInt64("block", 0);
1414 subMenu
->AddItem(fNativeMenuItem
= new BMenuItem("", message
, 'K'));
1415 fNativeMenuItem
->SetTarget(fHeaderView
);
1416 message
= new BMessage(*message
);
1417 subMenu
->AddItem(fSwappedMenuItem
= new BMenuItem("", message
, 'L'));
1418 fSwappedMenuItem
->SetTarget(fHeaderView
);
1419 menu
->AddItem(new BMenuItem(subMenu
));
1420 _UpdateSelectionMenuItems(0, 0);
1421 menu
->AddSeparatorItem();
1423 fBookmarkMenu
= new BMenu(B_TRANSLATE("Bookmarks"));
1424 fBookmarkMenu
->AddItem(item
= new BMenuItem(B_TRANSLATE("Add"),
1425 new BMessage(kMsgAddBookmark
), 'B'));
1426 item
->SetTarget(this);
1427 menu
->AddItem(new BMenuItem(fBookmarkMenu
));
1430 // "Attributes" menu (it's only visible if the underlying
1431 // file system actually supports attributes)
1433 BDirectory directory
;
1435 if (directory
.SetTo(&fEditor
.AttributeRef()) == B_OK
1436 && directory
.IsRootDirectory())
1437 directory
.GetVolume(&volume
);
1439 fEditor
.File().GetVolume(&volume
);
1441 if (!fEditor
.IsAttribute() && volume
.InitCheck() == B_OK
1442 && (volume
.KnowsMime() || volume
.KnowsAttr())) {
1443 bar
->AddItem(menu
= new BMenu(B_TRANSLATE("Attributes")));
1444 _UpdateAttributesMenu(menu
);
1449 menu
= new BMenu(B_TRANSLATE_COMMENT("View",
1450 "This is the last menubar item 'File Edit Block View'"));
1452 // Number Base (hex/decimal)
1454 subMenu
= new BMenu(B_TRANSLATE_COMMENT("Base", "A menu item, the number "
1455 "that is basis for a system of calculation. The base 10 system is a "
1456 "decimal system. This is in the same menu window than 'Font size' "
1457 "and 'BlockSize'"));
1458 message
= new BMessage(kMsgBaseType
);
1459 message
->AddInt32("base_type", kDecimalBase
);
1460 subMenu
->AddItem(item
= new BMenuItem(B_TRANSLATE_COMMENT("Decimal",
1461 "A menu item, as short as possible, noun is recommended if it is "
1462 "shorter than adjective."), message
, 'D'));
1463 item
->SetTarget(this);
1464 if (fHeaderView
->Base() == kDecimalBase
)
1465 item
->SetMarked(true);
1467 message
= new BMessage(kMsgBaseType
);
1468 message
->AddInt32("base_type", kHexBase
);
1469 subMenu
->AddItem(item
= new BMenuItem(B_TRANSLATE_COMMENT("Hex",
1470 "A menu item, as short as possible, noun is recommended if it is "
1471 "shorter than adjective."), message
, 'H'));
1472 item
->SetTarget(this);
1473 if (fHeaderView
->Base() == kHexBase
)
1474 item
->SetMarked(true);
1476 subMenu
->SetRadioMode(true);
1477 menu
->AddItem(new BMenuItem(subMenu
));
1481 subMenu
= new BMenu(B_TRANSLATE_COMMENT("Block size", "Menu item. "
1482 "This is in the same menu window than 'Base' and 'Font size'"));
1483 subMenu
->SetRadioMode(true);
1484 const uint32 blockSizes
[] = {512, 1024, 2048};
1485 for (uint32 i
= 0; i
< sizeof(blockSizes
) / sizeof(blockSizes
[0]); i
++) {
1487 snprintf(buffer
, sizeof(buffer
), "%" B_PRId32
"%s", blockSizes
[i
],
1488 fEditor
.IsDevice() && fEditor
.BlockSize() == blockSizes
[i
]
1489 ? B_TRANSLATE(" (native)") : "");
1490 subMenu
->AddItem(item
= new BMenuItem(buffer
,
1491 message
= new BMessage(kMsgBlockSize
)));
1492 message
->AddInt32("block_size", blockSizes
[i
]);
1493 if (fEditor
.BlockSize() == blockSizes
[i
])
1494 item
->SetMarked(true);
1496 if (subMenu
->FindMarked() == NULL
) {
1497 // if the device has some weird block size, we'll add it here, too
1499 snprintf(buffer
, sizeof(buffer
), B_TRANSLATE("%ld (native)"),
1500 fEditor
.BlockSize());
1501 subMenu
->AddItem(item
= new BMenuItem(buffer
,
1502 message
= new BMessage(kMsgBlockSize
)));
1503 message
->AddInt32("block_size", fEditor
.BlockSize());
1504 item
->SetMarked(true);
1506 subMenu
->SetTargetForItems(this);
1507 menu
->AddItem(new BMenuItem(subMenu
));
1508 menu
->AddSeparatorItem();
1512 subMenu
= new BMenu(B_TRANSLATE("Font size"));
1513 subMenu
->SetRadioMode(true);
1514 const int32 fontSizes
[] = {9, 10, 11, 12, 13, 14, 18, 24, 36, 48};
1515 int32 fontSize
= int32(fDataView
->FontSize() + 0.5);
1516 if (fDataView
->FontSizeFitsBounds())
1518 for (uint32 i
= 0; i
< sizeof(fontSizes
) / sizeof(fontSizes
[0]); i
++) {
1520 snprintf(buffer
, sizeof(buffer
), "%" B_PRId32
, fontSizes
[i
]);
1521 subMenu
->AddItem(item
= new BMenuItem(buffer
,
1522 message
= new BMessage(kMsgFontSize
)));
1523 message
->AddFloat("font_size", fontSizes
[i
]);
1524 if (fontSizes
[i
] == fontSize
)
1525 item
->SetMarked(true);
1527 subMenu
->AddSeparatorItem();
1528 subMenu
->AddItem(item
= new BMenuItem(B_TRANSLATE_COMMENT("Fit",
1529 "Size of fonts, fits to available room"),
1530 message
= new BMessage(kMsgFontSize
)));
1531 message
->AddFloat("font_size", 0.0f
);
1533 item
->SetMarked(true);
1535 subMenu
->SetTargetForItems(this);
1536 menu
->AddItem(new BMenuItem(subMenu
));
1543 ProbeView::AllAttached()
1545 fHeaderView
->SetTarget(fEditorLooper
);
1550 ProbeView::WindowActivated(bool active
)
1555 fDataView
->MakeFocus(true);
1557 // set this view as the current find panel's target
1558 BMessage
target(kMsgFindTarget
);
1559 target
.AddMessenger("target", this);
1560 be_app_messenger
.SendMessage(&target
);
1565 ProbeView::_UpdateSelectionMenuItems(int64 start
, int64 end
)
1568 const uint8
*data
= fDataView
->DataAt(start
);
1570 fNativeMenuItem
->SetEnabled(false);
1571 fSwappedMenuItem
->SetEnabled(false);
1575 // retrieve native endian position
1578 if (end
< start
+ 8)
1579 size
= end
+ 1 - start
;
1583 int64 bigEndianPosition
= 0;
1584 memcpy(&bigEndianPosition
, data
, size
);
1586 position
= B_BENDIAN_TO_HOST_INT64(bigEndianPosition
) >> (8 * (8 - size
));
1588 // update menu items
1591 if (fDataView
->Base() == kHexBase
) {
1592 snprintf(buffer
, sizeof(buffer
), B_TRANSLATE("Native: 0x%0*Lx"),
1593 size
* 2, position
);
1595 snprintf(buffer
, sizeof(buffer
), B_TRANSLATE("Native: %Ld (0x%0*Lx)"),
1596 position
, size
* 2, position
);
1599 fNativeMenuItem
->SetLabel(buffer
);
1600 fNativeMenuItem
->SetEnabled(position
>= 0
1601 && (off_t
)(position
* fEditor
.BlockSize()) < fEditor
.FileSize());
1602 fNativeMenuItem
->Message()->ReplaceInt64("block", position
);
1604 position
= B_SWAP_INT64(position
) >> (8 * (8 - size
));
1605 if (fDataView
->Base() == kHexBase
) {
1606 snprintf(buffer
, sizeof(buffer
), B_TRANSLATE("Swapped: 0x%0*Lx"),
1607 size
* 2, position
);
1609 snprintf(buffer
, sizeof(buffer
), B_TRANSLATE("Swapped: %Ld (0x%0*Lx)"),
1610 position
, size
* 2, position
);
1613 fSwappedMenuItem
->SetLabel(buffer
);
1614 fSwappedMenuItem
->SetEnabled(position
>= 0 && (off_t
)(position
* fEditor
.BlockSize()) < fEditor
.FileSize());
1615 fSwappedMenuItem
->Message()->ReplaceInt64("block", position
);
1620 ProbeView::_UpdateBookmarkMenuItems()
1622 for (int32 i
= 2; i
< fBookmarkMenu
->CountItems(); i
++) {
1623 BMenuItem
*item
= fBookmarkMenu
->ItemAt(i
);
1627 BMessage
*message
= item
->Message();
1628 if (message
== NULL
)
1631 off_t block
= message
->FindInt64("block");
1634 if (fDataView
->Base() == kHexBase
)
1635 snprintf(buffer
, sizeof(buffer
), B_TRANSLATE("Block 0x%Lx"), block
);
1637 snprintf(buffer
, sizeof(buffer
), B_TRANSLATE("Block %Ld (0x%Lx)"), block
, block
);
1639 item
->SetLabel(buffer
);
1645 ProbeView::_AddBookmark(off_t position
)
1647 int32 count
= fBookmarkMenu
->CountItems();
1650 fBookmarkMenu
->AddSeparatorItem();
1654 // insert current position as bookmark
1656 off_t block
= position
/ fEditor
.BlockSize();
1658 off_t bookmark
= -1;
1661 for (i
= 2; (item
= fBookmarkMenu
->ItemAt(i
)) != NULL
; i
++) {
1662 BMessage
*message
= item
->Message();
1663 if (message
!= NULL
&& message
->FindInt64("block", &bookmark
) == B_OK
) {
1664 if (block
<= bookmark
)
1669 // the bookmark already exists
1670 if (block
== bookmark
)
1674 if (fDataView
->Base() == kHexBase
)
1675 snprintf(buffer
, sizeof(buffer
), B_TRANSLATE("Block 0x%Lx"), block
);
1677 snprintf(buffer
, sizeof(buffer
), B_TRANSLATE("Block %Ld (0x%Lx)"), block
, block
);
1680 item
= new BMenuItem(buffer
, message
= new BMessage(kMsgPositionUpdate
));
1681 item
->SetTarget(fHeaderView
);
1683 item
->SetShortcut('0' + count
- 2, B_COMMAND_KEY
);
1684 message
->AddInt64("block", block
);
1686 fBookmarkMenu
->AddItem(item
, i
);
1691 ProbeView::_RemoveTypeEditor()
1693 if (fTypeView
== NULL
)
1696 if (Parent() != NULL
)
1697 Parent()->RemoveChild(fTypeView
);
1699 Window()->RemoveChild(fTypeView
);
1707 ProbeView::_SetTypeEditor(int32 index
)
1710 // remove type editor, show raw editor
1714 _RemoveTypeEditor();
1716 // hide raw editor, create and show type editor
1720 _RemoveTypeEditor();
1722 fTypeView
= new TypeView(Frame(), "type shell", index
, fEditor
,
1725 if (Parent() != NULL
)
1726 Parent()->AddChild(fTypeView
);
1728 Window()->AddChild(fTypeView
);
1734 ProbeView::_CheckClipboard()
1736 if (!be_clipboard
->Lock())
1739 bool hasData
= false;
1741 if ((clip
= be_clipboard
->Data()) != NULL
) {
1744 if (clip
->FindData(B_FILE_MIME_TYPE
, B_MIME_TYPE
, &data
, &size
) == B_OK
1745 || clip
->FindData("text/plain", B_MIME_TYPE
, &data
, &size
) == B_OK
)
1749 be_clipboard
->Unlock();
1751 fPasteMenuItem
->SetEnabled(hasData
);
1756 ProbeView::_PageSetup()
1758 BPrintJob
printJob(Window()->Title());
1759 if (fPrintSettings
!= NULL
)
1760 printJob
.SetSettings(new BMessage(*fPrintSettings
));
1762 status_t status
= printJob
.ConfigPage();
1763 if (status
== B_OK
) {
1764 // replace the print settings on success
1765 delete fPrintSettings
;
1766 fPrintSettings
= printJob
.Settings();
1776 if (fPrintSettings
== NULL
&& _PageSetup() != B_OK
)
1779 BPrintJob
printJob(Window()->Title());
1780 printJob
.SetSettings(new BMessage(*fPrintSettings
));
1782 if (printJob
.ConfigJob() == B_OK
) {
1783 BRect rect
= printJob
.PrintableRect();
1785 float width
, height
;
1786 fDataView
->GetPreferredSize(&width
, &height
);
1788 printJob
.BeginJob();
1790 fDataView
->SetScale(rect
.Width() / width
);
1791 printJob
.DrawView(fDataView
, rect
, rect
.LeftTop());
1792 fDataView
->SetScale(1.0);
1793 printJob
.SpoolPage();
1795 printJob
.CommitJob();
1803 status_t status
= fEditor
.Save();
1808 snprintf(buffer
, sizeof(buffer
),
1809 B_TRANSLATE("Writing to the file failed:\n"
1811 "All changes will be lost when you quit."),
1814 BAlert
* alert
= new BAlert(B_TRANSLATE("DiskProbe request"),
1815 buffer
, B_TRANSLATE("OK"), NULL
, NULL
,
1816 B_WIDTH_AS_USUAL
, B_WARNING_ALERT
);
1817 alert
->SetFlags(alert
->Flags() | B_CLOSE_ON_ESCAPE
);
1825 ProbeView::QuitRequested()
1827 fEditorLooper
->QuitFind();
1829 if (!fEditor
.IsModified())
1832 BAlert
* alert
= new BAlert(B_TRANSLATE("DiskProbe request"),
1833 B_TRANSLATE("Save changes before closing?"), B_TRANSLATE("Cancel"),
1834 B_TRANSLATE("Don't save"), B_TRANSLATE("Save"), B_WIDTH_AS_USUAL
,
1835 B_OFFSET_SPACING
, B_WARNING_ALERT
);
1836 alert
->SetShortcut(0, B_ESCAPE
);
1837 alert
->SetShortcut(1, 'd');
1838 alert
->SetShortcut(2, 's');
1839 int32 chosen
= alert
->Go();
1846 return _Save() == B_OK
;
1851 ProbeView::MessageReceived(BMessage
*message
)
1853 switch (message
->what
) {
1854 case B_SAVE_REQUESTED
:
1858 case B_OBSERVER_NOTICE_CHANGE
: {
1860 if (message
->FindInt32(B_OBSERVE_WHAT_CHANGE
, &what
) != B_OK
)
1864 case kDataViewSelection
:
1867 if (message
->FindInt64("start", &start
) == B_OK
1868 && message
->FindInt64("end", &end
) == B_OK
)
1869 _UpdateSelectionMenuItems(start
, end
);
1879 if (message
->FindInt32("base_type", &type
) != B_OK
)
1882 fHeaderView
->SetBase((base_type
)type
);
1883 fDataView
->SetBase((base_type
)type
);
1885 // The selection menu items depend on the base type as well
1887 fDataView
->GetSelection(start
, end
);
1888 _UpdateSelectionMenuItems(start
, end
);
1890 _UpdateBookmarkMenuItems();
1892 // update the application's settings
1893 BMessage
update(*message
);
1894 update
.what
= kMsgSettingsChanged
;
1895 be_app_messenger
.SendMessage(&update
);
1902 if (message
->FindFloat("font_size", &size
) != B_OK
)
1905 fDataView
->SetFontSize(size
);
1907 // update the application's settings
1908 BMessage
update(*message
);
1909 update
.what
= kMsgSettingsChanged
;
1910 be_app_messenger
.SendMessage(&update
);
1917 if (message
->FindInt32("block_size", &blockSize
) != B_OK
)
1920 BAutolock
locker(fEditor
);
1922 if (fEditor
.SetViewSize(blockSize
) == B_OK
1923 && fEditor
.SetBlockSize(blockSize
) == B_OK
)
1924 fHeaderView
->SetTo(fEditor
.ViewOffset(), blockSize
);
1931 if (message
->FindInt32("editor index", &index
) != B_OK
)
1934 _SetTypeEditor(index
);
1938 case kMsgAddBookmark
:
1939 _AddBookmark(fHeaderView
->Position());
1950 case kMsgOpenFindWindow
:
1952 fEditorLooper
->QuitFind();
1954 // set this view as the current find panel's target
1955 BMessage
find(*fFindAgainMenuItem
->Message());
1956 find
.what
= kMsgOpenFindWindow
;
1957 find
.AddMessenger("target", this);
1958 be_app_messenger
.SendMessage(&find
);
1966 if (message
->FindData("data", B_RAW_TYPE
, (const void **)&data
, &size
) != B_OK
) {
1967 // search again for last pattern
1968 BMessage
*itemMessage
= fFindAgainMenuItem
->Message();
1969 if (itemMessage
== NULL
1970 || itemMessage
->FindData("data", B_RAW_TYPE
, (const void **)&data
, &size
) != B_OK
) {
1971 // this shouldn't ever happen, but well...
1976 // remember the search pattern
1977 fFindAgainMenuItem
->SetMessage(new BMessage(*message
));
1978 fFindAgainMenuItem
->SetEnabled(true);
1982 fDataView
->GetSelection(start
, end
);
1984 BMessage
find(*message
);
1985 find
.AddInt64("start", fHeaderView
->Position() + start
+ 1);
1986 find
.AddMessenger("progress_monitor", BMessenger(fHeaderView
));
1987 fEditorLooper
->PostMessage(&find
);
1992 fEditorLooper
->QuitFind();
1995 case B_NODE_MONITOR
:
1997 switch (message
->FindInt32("opcode")) {
1998 case B_STAT_CHANGED
:
1999 fEditor
.ForceUpdate();
2001 case B_ATTR_CHANGED
:
2004 if (message
->FindString("attr", &name
) != B_OK
)
2007 if (fEditor
.IsAttribute()) {
2008 if (!strcmp(name
, fEditor
.Attribute()))
2009 fEditor
.ForceUpdate();
2011 BMenuBar
*bar
= Window()->KeyMenuBar();
2013 BMenuItem
*item
= bar
->FindItem("Attributes");
2014 if (item
!= NULL
&& item
->Submenu() != NULL
)
2015 _UpdateAttributesMenu(item
->Submenu());
2019 // There might be a new icon
2020 if (!strcmp(name
, "BEOS:TYPE")
2021 || !strcmp(name
, "BEOS:M:STD_ICON")
2022 || !strcmp(name
, "BEOS:L:STD_ICON")
2023 || !strcmp(name
, "BEOS:ICON"))
2024 fHeaderView
->UpdateIcon();
2031 case B_CLIPBOARD_CHANGED
:
2035 case kMsgDataEditorStateChange
:
2038 if (message
->FindBool("can_undo", &enabled
) == B_OK
)
2039 fUndoMenuItem
->SetEnabled(enabled
);
2041 if (message
->FindBool("can_redo", &enabled
) == B_OK
)
2042 fRedoMenuItem
->SetEnabled(enabled
);
2044 if (message
->FindBool("modified", &enabled
) == B_OK
)
2045 fSaveMenuItem
->SetEnabled(enabled
);
2050 BView::MessageReceived(message
);