vfs: check userland buffers before reading them.
[haiku.git] / src / apps / diskprobe / TypeEditors.cpp
blob6cbb581280572d9352382859587b4e38aefb58f9
1 /*
2 * Copyright 2004-2008, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
3 * Distributed under the terms of the MIT License.
4 */
7 #include "TypeEditors.h"
8 #include "DataEditor.h"
10 #include <stdio.h>
11 #include <stdlib.h>
13 #include <Alert.h>
14 #include <Autolock.h>
15 #include <Bitmap.h>
16 #include <Catalog.h>
17 #include <IconUtils.h>
18 #include <LayoutBuilder.h>
19 #include <Locale.h>
20 #include <MenuField.h>
21 #include <MenuItem.h>
22 #include <Mime.h>
23 #include <PopUpMenu.h>
24 #include <ScrollBar.h>
25 #include <ScrollView.h>
26 #include <Slider.h>
27 #include <String.h>
28 #include <StringView.h>
29 #include <TextControl.h>
30 #include <TextView.h>
31 #include <TranslationUtils.h>
32 #include <TranslatorFormats.h>
35 #undef B_TRANSLATION_CONTEXT
36 #define B_TRANSLATION_CONTEXT "TypeEditors"
38 static const uint32 kMsgValueChanged = 'vlch';
39 static const uint32 kMsgScaleChanged = 'scch';
40 static const uint32 kMimeTypeItem = 'miti';
43 class StringEditor : public TypeEditorView {
44 public:
45 StringEditor(DataEditor& editor);
47 virtual void AttachedToWindow();
48 virtual void DetachedFromWindow();
49 virtual void MessageReceived(BMessage* message);
51 virtual void CommitChanges();
53 private:
54 void _UpdateText();
56 BTextView* fTextView;
57 BString fPreviousText;
61 class MimeTypeEditor : public TypeEditorView {
62 public:
63 MimeTypeEditor(BRect rect, DataEditor& editor);
65 virtual void AttachedToWindow();
66 virtual void DetachedFromWindow();
67 virtual void MessageReceived(BMessage* message);
69 virtual void CommitChanges();
70 virtual bool TypeMatches();
72 private:
73 void _UpdateText();
75 BTextControl* fTextControl;
76 BString fPreviousText;
80 class NumberEditor : public TypeEditorView {
81 public:
82 NumberEditor(BRect rect, DataEditor& editor);
84 virtual void AttachedToWindow();
85 virtual void DetachedFromWindow();
86 virtual void MessageReceived(BMessage* message);
88 virtual void CommitChanges();
89 virtual bool TypeMatches();
91 private:
92 void _UpdateText();
93 const char* _TypeLabel();
94 status_t _Format(char* buffer);
95 size_t _Size();
97 BTextControl* fTextControl;
98 BString fPreviousText;
102 class BooleanEditor : public TypeEditorView {
103 public:
104 BooleanEditor(BRect rect, DataEditor& editor);
106 virtual void AttachedToWindow();
107 virtual void DetachedFromWindow();
108 virtual void MessageReceived(BMessage* message);
110 virtual void CommitChanges();
111 virtual bool TypeMatches();
113 private:
114 void _UpdateMenuField();
116 BMenuItem* fFalseMenuItem;
117 BMenuItem* fTrueMenuItem;
121 class ImageView : public TypeEditorView {
122 public:
123 ImageView(DataEditor &editor);
124 virtual ~ImageView();
126 virtual void AttachedToWindow();
127 virtual void DetachedFromWindow();
128 virtual void MessageReceived(BMessage *message);
129 virtual void Draw(BRect updateRect);
131 private:
132 void _UpdateImage();
134 BBitmap* fBitmap;
135 BStringView* fDescriptionView;
136 BSlider* fScaleSlider;
140 class MessageView : public TypeEditorView {
141 public:
142 MessageView(BRect rect, DataEditor& editor);
143 virtual ~MessageView();
145 virtual void AttachedToWindow();
146 virtual void DetachedFromWindow();
147 virtual void MessageReceived(BMessage* message);
149 void SetTo(BMessage& message);
151 private:
152 BString _TypeToString(type_code type);
153 void _UpdateMessage();
155 BTextView* fTextView;
159 // #pragma mark - TypeEditorView
162 TypeEditorView::TypeEditorView(BRect rect, const char *name,
163 uint32 resizingMode, uint32 flags, DataEditor& editor)
164 : BView(rect, name, resizingMode, flags),
165 fEditor(editor)
170 TypeEditorView::TypeEditorView(const char *name, uint32 flags,
171 DataEditor& editor)
172 : BView(name, flags),
173 fEditor(editor)
178 TypeEditorView::~TypeEditorView()
183 void
184 TypeEditorView::CommitChanges()
186 // the default just does nothing here
190 bool
191 TypeEditorView::TypeMatches()
193 // the default is to accept anything that easily fits into memory
195 system_info info;
196 get_system_info(&info);
198 return uint64(fEditor.FileSize()) / B_PAGE_SIZE < info.max_pages / 2;
202 // #pragma mark - StringEditor
205 StringEditor::StringEditor(DataEditor& editor)
206 : TypeEditorView(B_TRANSLATE("String editor"), 0, editor)
208 SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
209 SetLayout(new BGroupLayout(B_VERTICAL));
211 BStringView *stringView = new BStringView(B_EMPTY_STRING,
212 B_TRANSLATE("Contents:"));
213 stringView->ResizeToPreferred();
214 AddChild(stringView);
216 fTextView = new BTextView(B_EMPTY_STRING, B_WILL_DRAW);
218 BScrollView* scrollView = new BScrollView("scroller", fTextView,
219 B_WILL_DRAW, true, true);
220 AddChild(scrollView);
224 void
225 StringEditor::_UpdateText()
227 BAutolock locker(fEditor);
229 size_t viewSize = fEditor.ViewSize();
230 // that may need some more memory...
231 if ((off_t)viewSize < fEditor.FileSize())
232 fEditor.SetViewSize(fEditor.FileSize());
234 const char *buffer;
235 if (fEditor.GetViewBuffer((const uint8 **)&buffer) == B_OK) {
236 fTextView->SetText(buffer);
237 fPreviousText.SetTo(buffer);
240 // restore old view size
241 fEditor.SetViewSize(viewSize);
245 void
246 StringEditor::CommitChanges()
248 if (fPreviousText != fTextView->Text()) {
249 fEditor.Replace(0, (const uint8 *)fTextView->Text(),
250 fTextView->TextLength() + 1);
255 void
256 StringEditor::AttachedToWindow()
258 fEditor.StartWatching(this);
260 _UpdateText();
264 void
265 StringEditor::DetachedFromWindow()
267 fEditor.StopWatching(this);
269 CommitChanges();
273 void
274 StringEditor::MessageReceived(BMessage *message)
276 BView::MessageReceived(message);
280 // #pragma mark - MimeTypeEditor
283 MimeTypeEditor::MimeTypeEditor(BRect rect, DataEditor& editor)
284 : TypeEditorView(rect, B_TRANSLATE("MIME type editor"), B_FOLLOW_LEFT_RIGHT, 0, editor)
286 SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
288 fTextControl = new BTextControl(rect.InsetByCopy(5, 5), B_EMPTY_STRING,
289 B_TRANSLATE("MIME type:"), NULL, new BMessage(kMsgValueChanged), B_FOLLOW_ALL);
290 fTextControl->SetDivider(StringWidth(fTextControl->Label()) + 8);
292 float width, height;
293 fTextControl->GetPreferredSize(&width, &height);
294 fTextControl->ResizeTo(rect.Width() - 10, height);
296 ResizeTo(rect.Width(), height + 10);
298 AddChild(fTextControl);
302 void
303 MimeTypeEditor::_UpdateText()
305 BAutolock locker(fEditor);
307 const char* mimeType;
308 if (fEditor.GetViewBuffer((const uint8 **)&mimeType) == B_OK) {
309 fTextControl->SetText(mimeType);
310 fPreviousText.SetTo(mimeType);
315 void
316 MimeTypeEditor::CommitChanges()
318 if (fPreviousText != fTextControl->Text()) {
319 fEditor.Replace(0, (const uint8*)fTextControl->Text(),
320 strlen(fTextControl->Text()) + 1);
325 bool
326 MimeTypeEditor::TypeMatches()
328 // TODO: check contents?
329 return fEditor.FileSize() <= B_MIME_TYPE_LENGTH;
333 void
334 MimeTypeEditor::AttachedToWindow()
336 fTextControl->SetTarget(this);
337 fEditor.StartWatching(this);
339 _UpdateText();
343 void
344 MimeTypeEditor::DetachedFromWindow()
346 fEditor.StopWatching(this);
348 CommitChanges();
352 void
353 MimeTypeEditor::MessageReceived(BMessage *message)
355 switch (message->what) {
356 case kMsgValueChanged:
357 fEditor.Replace(0, (const uint8 *)fTextControl->Text(),
358 strlen(fTextControl->Text()) + 1);
359 break;
361 case kMsgDataEditorUpdate:
362 _UpdateText();
363 break;
365 default:
366 BView::MessageReceived(message);
371 // #pragma mark - NumberEditor
374 NumberEditor::NumberEditor(BRect rect, DataEditor &editor)
375 : TypeEditorView(rect, B_TRANSLATE("Number editor"), B_FOLLOW_LEFT_RIGHT, 0, editor)
377 SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
379 fTextControl = new BTextControl(rect.InsetByCopy(5, 5), B_EMPTY_STRING,
380 _TypeLabel(), NULL, new BMessage(kMsgValueChanged), B_FOLLOW_ALL);
381 fTextControl->SetDivider(StringWidth(fTextControl->Label()) + 8);
382 fTextControl->SetAlignment(B_ALIGN_RIGHT, B_ALIGN_RIGHT);
383 ResizeTo(rect.Width(), 30);
385 AddChild(fTextControl);
389 void
390 NumberEditor::_UpdateText()
392 if (fEditor.Lock()) {
393 const char* number;
394 if (fEditor.GetViewBuffer((const uint8**)&number) == B_OK) {
395 char buffer[64];
396 char format[16];
397 switch (fEditor.Type()) {
398 case B_FLOAT_TYPE:
400 float value = *(float*)number;
401 snprintf(buffer, sizeof(buffer), "%g", value);
402 break;
404 case B_DOUBLE_TYPE:
406 double value = *(double *)number;
407 snprintf(buffer, sizeof(buffer), "%g", value);
408 break;
410 case B_SSIZE_T_TYPE:
411 case B_INT8_TYPE:
412 case B_INT16_TYPE:
413 case B_INT32_TYPE:
414 case B_INT64_TYPE:
415 case B_OFF_T_TYPE:
417 _Format(format);
418 switch (_Size()) {
419 case 1:
421 int8 value = *(int8 *)number;
422 snprintf(buffer, sizeof(buffer), format, value);
423 break;
425 case 2:
427 int16 value = *(int16 *)number;
428 snprintf(buffer, sizeof(buffer), format, value);
429 break;
431 case 4:
433 int32 value = *(int32 *)number;
434 snprintf(buffer, sizeof(buffer), format, value);
435 break;
437 case 8:
439 int64 value = *(int64 *)number;
440 snprintf(buffer, sizeof(buffer), format, value);
441 break;
444 break;
447 default:
449 _Format(format);
450 switch (_Size()) {
451 case 1:
453 uint8 value = *(uint8 *)number;
454 snprintf(buffer, sizeof(buffer), format, value);
455 break;
457 case 2:
459 uint16 value = *(uint16 *)number;
460 snprintf(buffer, sizeof(buffer), format, value);
461 break;
463 case 4:
465 uint32 value = *(uint32 *)number;
466 snprintf(buffer, sizeof(buffer), format, value);
467 break;
469 case 8:
471 uint64 value = *(uint64 *)number;
472 snprintf(buffer, sizeof(buffer), format, value);
473 break;
476 break;
479 fTextControl->SetText(buffer);
480 fPreviousText.SetTo(buffer);
483 fEditor.Unlock();
488 bool
489 NumberEditor::TypeMatches()
491 return fEditor.FileSize() >= (off_t)_Size();
492 // we only look at as many bytes we need to
496 void
497 NumberEditor::CommitChanges()
499 if (fPreviousText == fTextControl->Text())
500 return;
502 const char *number = fTextControl->Text();
503 uint8 buffer[8];
505 switch (fEditor.Type()) {
506 case B_FLOAT_TYPE:
508 float value = strtod(number, NULL);
509 *(float *)buffer = value;
510 break;
512 case B_DOUBLE_TYPE:
514 double value = strtod(number, NULL);
515 *(double *)buffer = value;
516 break;
518 case B_INT8_TYPE:
520 int64 value = strtoll(number, NULL, 0);
521 if (value > CHAR_MAX)
522 value = CHAR_MAX;
523 else if (value < CHAR_MIN)
524 value = CHAR_MIN;
525 *(int8 *)buffer = (int8)value;
526 break;
528 case B_UINT8_TYPE:
530 int64 value = strtoull(number, NULL, 0);
531 if (value > UCHAR_MAX)
532 value = UCHAR_MAX;
533 *(uint8 *)buffer = (uint8)value;
534 break;
536 case B_INT16_TYPE:
538 int64 value = strtoll(number, NULL, 0);
539 if (value > SHRT_MAX)
540 value = SHRT_MAX;
541 else if (value < SHRT_MIN)
542 value = SHRT_MIN;
543 *(int16 *)buffer = (int16)value;
544 break;
546 case B_UINT16_TYPE:
548 int64 value = strtoull(number, NULL, 0);
549 if (value > USHRT_MAX)
550 value = USHRT_MAX;
551 *(uint16 *)buffer = (uint16)value;
552 break;
554 case B_INT32_TYPE:
555 case B_SSIZE_T_TYPE:
557 int64 value = strtoll(number, NULL, 0);
558 if (value > LONG_MAX)
559 value = LONG_MAX;
560 else if (value < LONG_MIN)
561 value = LONG_MIN;
562 *(int32 *)buffer = (int32)value;
563 break;
565 case B_UINT32_TYPE:
566 case B_SIZE_T_TYPE:
567 case B_POINTER_TYPE:
569 uint64 value = strtoull(number, NULL, 0);
570 if (value > ULONG_MAX)
571 value = ULONG_MAX;
572 *(uint32 *)buffer = (uint32)value;
573 break;
575 case B_INT64_TYPE:
576 case B_OFF_T_TYPE:
578 int64 value = strtoll(number, NULL, 0);
579 *(int64 *)buffer = value;
580 break;
582 case B_UINT64_TYPE:
584 uint64 value = strtoull(number, NULL, 0);
585 *(uint64 *)buffer = value;
586 break;
588 default:
589 return;
592 fEditor.Replace(0, buffer, _Size());
593 fPreviousText.SetTo((char *)buffer);
597 const char*
598 NumberEditor::_TypeLabel()
600 switch (fEditor.Type()) {
601 case B_INT8_TYPE:
602 return B_TRANSLATE("8 bit signed value:");
603 case B_UINT8_TYPE:
604 return B_TRANSLATE("8 bit unsigned value:");
605 case B_INT16_TYPE:
606 return B_TRANSLATE("16 bit signed value:");
607 case B_UINT16_TYPE:
608 return B_TRANSLATE("16 bit unsigned value:");
609 case B_INT32_TYPE:
610 return B_TRANSLATE("32 bit signed value:");
611 case B_UINT32_TYPE:
612 return B_TRANSLATE("32 bit unsigned value:");
613 case B_INT64_TYPE:
614 return B_TRANSLATE("64 bit signed value:");
615 case B_UINT64_TYPE:
616 return B_TRANSLATE("64 bit unsigned value:");
617 case B_FLOAT_TYPE:
618 return B_TRANSLATE("Floating-point value:");
619 case B_DOUBLE_TYPE:
620 return B_TRANSLATE("Double precision floating-point value:");
621 case B_SSIZE_T_TYPE:
622 return B_TRANSLATE("32 bit size or status:");
623 case B_SIZE_T_TYPE:
624 return B_TRANSLATE("32 bit unsigned size:");
625 case B_OFF_T_TYPE:
626 return B_TRANSLATE("64 bit signed offset:");
627 case B_POINTER_TYPE:
628 return B_TRANSLATE("32 bit unsigned pointer:");
629 default:
630 return B_TRANSLATE("Number:");
635 size_t
636 NumberEditor::_Size()
638 switch (fEditor.Type()) {
639 case B_INT8_TYPE:
640 case B_UINT8_TYPE:
641 return 1;
642 case B_INT16_TYPE:
643 case B_UINT16_TYPE:
644 return 2;
645 case B_SSIZE_T_TYPE:
646 case B_INT32_TYPE:
647 case B_SIZE_T_TYPE:
648 case B_POINTER_TYPE:
649 case B_UINT32_TYPE:
650 return 4;
651 case B_INT64_TYPE:
652 case B_OFF_T_TYPE:
653 case B_UINT64_TYPE:
654 return 8;
655 case B_FLOAT_TYPE:
656 return 4;
657 case B_DOUBLE_TYPE:
658 return 8;
660 default:
661 return 0;
666 status_t
667 NumberEditor::_Format(char *buffer)
669 switch (fEditor.Type()) {
670 case B_INT8_TYPE:
671 strcpy(buffer, "%hd");
672 return B_OK;
673 case B_UINT8_TYPE:
674 strcpy(buffer, "%hu");
675 return B_OK;
676 case B_INT16_TYPE:
677 strcpy(buffer, "%hd");
678 return B_OK;
679 case B_UINT16_TYPE:
680 strcpy(buffer, "%hu");
681 return B_OK;
682 case B_SSIZE_T_TYPE:
683 case B_INT32_TYPE:
684 strcpy(buffer, "%ld");
685 return B_OK;
686 case B_SIZE_T_TYPE:
687 case B_POINTER_TYPE:
688 case B_UINT32_TYPE:
689 strcpy(buffer, "%lu");
690 return B_OK;
691 case B_INT64_TYPE:
692 case B_OFF_T_TYPE:
693 strcpy(buffer, "%Ld");
694 return B_OK;
695 case B_UINT64_TYPE:
696 strcpy(buffer, "%Lu");
697 return B_OK;
698 case B_FLOAT_TYPE:
699 strcpy(buffer, "%g");
700 return B_OK;
701 case B_DOUBLE_TYPE:
702 strcpy(buffer, "%lg");
703 return B_OK;
705 default:
706 return B_ERROR;
711 void
712 NumberEditor::AttachedToWindow()
714 fTextControl->SetTarget(this);
715 fEditor.StartWatching(this);
717 _UpdateText();
721 void
722 NumberEditor::DetachedFromWindow()
724 fEditor.StopWatching(this);
726 CommitChanges();
730 void
731 NumberEditor::MessageReceived(BMessage *message)
733 switch (message->what) {
734 case kMsgValueChanged:
735 CommitChanges();
736 break;
737 case kMsgDataEditorUpdate:
738 _UpdateText();
739 break;
741 default:
742 BView::MessageReceived(message);
747 // #pragma mark - BooleanEditor
750 BooleanEditor::BooleanEditor(BRect rect, DataEditor &editor)
751 : TypeEditorView(rect, B_TRANSLATE("Boolean editor"), B_FOLLOW_NONE, 0, editor)
753 SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
755 BPopUpMenu *menu = new BPopUpMenu("bool");
756 BMessage *message;
757 menu->AddItem(fFalseMenuItem = new BMenuItem("false",
758 new BMessage(kMsgValueChanged)));
759 menu->AddItem(fTrueMenuItem = new BMenuItem("true",
760 message = new BMessage(kMsgValueChanged)));
761 message->AddInt8("value", 1);
763 BMenuField *menuField = new BMenuField(rect.InsetByCopy(5, 5),
764 B_EMPTY_STRING, B_TRANSLATE("Boolean value:"), menu, B_FOLLOW_LEFT_RIGHT);
765 menuField->SetDivider(StringWidth(menuField->Label()) + 8);
766 menuField->ResizeToPreferred();
767 ResizeTo(menuField->Bounds().Width() + 10,
768 menuField->Bounds().Height() + 10);
770 _UpdateMenuField();
772 AddChild(menuField);
776 bool
777 BooleanEditor::TypeMatches()
779 // we accept everything: we just look at the first byte, anyway
780 return true;
784 void
785 BooleanEditor::_UpdateMenuField()
787 if (fEditor.FileSize() != 1)
788 return;
790 if (fEditor.Lock()) {
791 const char *buffer;
792 if (fEditor.GetViewBuffer((const uint8 **)&buffer) == B_OK)
793 (buffer[0] != 0 ? fTrueMenuItem : fFalseMenuItem)->SetMarked(true);
795 fEditor.Unlock();
800 void
801 BooleanEditor::CommitChanges()
803 // we're commiting the changes as they happen
807 void
808 BooleanEditor::AttachedToWindow()
810 fTrueMenuItem->SetTarget(this);
811 fFalseMenuItem->SetTarget(this);
813 fEditor.StartWatching(this);
817 void
818 BooleanEditor::DetachedFromWindow()
820 fEditor.StopWatching(this);
824 void
825 BooleanEditor::MessageReceived(BMessage *message)
827 switch (message->what) {
828 case kMsgValueChanged:
830 uint8 boolean = message->FindInt8("value");
831 fEditor.Replace(0, (const uint8 *)&boolean, 1);
832 break;
834 case kMsgDataEditorUpdate:
835 _UpdateMenuField();
836 break;
838 default:
839 BView::MessageReceived(message);
844 // #pragma mark - ImageView
847 ImageView::ImageView(DataEditor &editor)
848 : TypeEditorView(B_TRANSLATE_COMMENT("Image view", "Image means here a "
849 "picture file, not a disk image."),
850 B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE, editor),
851 fBitmap(NULL),
852 fScaleSlider(NULL)
854 if (editor.Type() == B_MINI_ICON_TYPE
855 || editor.Type() == B_LARGE_ICON_TYPE
856 #ifdef HAIKU_TARGET_PLATFORM_HAIKU
857 || editor.Type() == B_VECTOR_ICON_TYPE
858 #endif
860 SetName(B_TRANSLATE("Icon view"));
862 fDescriptionView = new BStringView("",
863 B_TRANSLATE_COMMENT("Could not read image", "Image means "
864 "here a picture file, not a disk image."));
865 fDescriptionView->SetAlignment(B_ALIGN_CENTER);
867 if (editor.Type() == B_VECTOR_ICON_TYPE) {
868 // vector icon
869 fScaleSlider = new BSlider("", NULL,
870 new BMessage(kMsgScaleChanged), 2, 32, B_HORIZONTAL);
871 fScaleSlider->SetModificationMessage(new BMessage(kMsgScaleChanged));
872 fScaleSlider->ResizeToPreferred();
873 fScaleSlider->SetValue(8);
874 fScaleSlider->SetHashMarks(B_HASH_MARKS_BOTH);
875 fScaleSlider->SetHashMarkCount(15);
877 BLayoutBuilder::Group<>(this, B_HORIZONTAL)
878 .SetInsets(B_USE_WINDOW_SPACING, 256, B_USE_WINDOW_SPACING,
879 B_H_SCROLL_BAR_HEIGHT) // Leave space for the icon
880 .AddGlue()
881 .AddGroup(B_VERTICAL)
882 .Add(fDescriptionView)
883 .Add(fScaleSlider)
884 .End()
885 .AddGlue();
886 } else {
887 BLayoutBuilder::Group<>(this, B_HORIZONTAL)
888 .SetInsets(B_USE_WINDOW_SPACING, 256, B_USE_WINDOW_SPACING,
889 B_USE_WINDOW_SPACING) // Leave space for the icon
890 .AddGlue()
891 .Add(fDescriptionView)
892 .AddGlue();
897 ImageView::~ImageView()
899 delete fBitmap;
903 void
904 ImageView::AttachedToWindow()
906 if (Parent() != NULL)
907 SetViewColor(Parent()->ViewColor());
908 else
909 SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
911 fEditor.StartWatching(this);
912 if (fScaleSlider != NULL)
913 fScaleSlider->SetTarget(this);
915 _UpdateImage();
919 void
920 ImageView::DetachedFromWindow()
922 fEditor.StopWatching(this);
926 void
927 ImageView::MessageReceived(BMessage *message)
929 switch (message->what) {
930 case kMsgDataEditorUpdate:
931 _UpdateImage();
932 break;
934 case kMsgScaleChanged:
935 _UpdateImage();
936 break;
938 default:
939 BView::MessageReceived(message);
944 void
945 ImageView::Draw(BRect updateRect)
947 if (fBitmap != NULL) {
948 SetDrawingMode(B_OP_ALPHA);
949 DrawBitmap(fBitmap, BPoint((Bounds().Width() - fBitmap->Bounds().Width()) / 2, 0));
950 SetDrawingMode(B_OP_COPY);
955 void
956 ImageView::_UpdateImage()
958 // ToDo: add scroller if necessary?!
960 BAutolock locker(fEditor);
962 // we need all the data...
964 size_t viewSize = fEditor.ViewSize();
965 // that may need some more memory...
966 if ((off_t)viewSize < fEditor.FileSize())
967 fEditor.SetViewSize(fEditor.FileSize());
969 const char *data;
970 if (fEditor.GetViewBuffer((const uint8 **)&data) != B_OK) {
971 fEditor.SetViewSize(viewSize);
972 return;
975 if (fBitmap != NULL && (fEditor.Type() == B_MINI_ICON_TYPE
976 || fEditor.Type() == B_LARGE_ICON_TYPE)) {
977 // optimize icon update...
978 fBitmap->SetBits(data, fEditor.FileSize(), 0, B_CMAP8);
979 fEditor.SetViewSize(viewSize);
980 return;
982 #ifdef HAIKU_TARGET_PLATFORM_HAIKU
983 if (fBitmap != NULL && fEditor.Type() == B_VECTOR_ICON_TYPE
984 && fScaleSlider->Value() * 8 - 1 == fBitmap->Bounds().Width()) {
985 if (BIconUtils::GetVectorIcon((const uint8 *)data,
986 (size_t)fEditor.FileSize(), fBitmap) == B_OK) {
987 fEditor.SetViewSize(viewSize);
988 return;
991 #endif
993 delete fBitmap;
994 fBitmap = NULL;
996 switch (fEditor.Type()) {
997 case B_MINI_ICON_TYPE:
998 fBitmap = new BBitmap(BRect(0, 0, 15, 15), B_CMAP8);
999 if (fBitmap->InitCheck() == B_OK)
1000 fBitmap->SetBits(data, fEditor.FileSize(), 0, B_CMAP8);
1001 break;
1002 case B_LARGE_ICON_TYPE:
1003 fBitmap = new BBitmap(BRect(0, 0, 31, 31), B_CMAP8);
1004 if (fBitmap->InitCheck() == B_OK)
1005 fBitmap->SetBits(data, fEditor.FileSize(), 0, B_CMAP8);
1006 break;
1007 #ifdef HAIKU_TARGET_PLATFORM_HAIKU
1008 case B_VECTOR_ICON_TYPE:
1009 fBitmap = new BBitmap(BRect(0, 0, fScaleSlider->Value() * 8 - 1,
1010 fScaleSlider->Value() * 8 - 1), B_RGB32);
1011 if (fBitmap->InitCheck() != B_OK
1012 || BIconUtils::GetVectorIcon((const uint8 *)data,
1013 (size_t)fEditor.FileSize(), fBitmap) != B_OK) {
1014 delete fBitmap;
1015 fBitmap = NULL;
1017 break;
1018 #endif
1019 case B_PNG_FORMAT:
1021 BMemoryIO stream(data, fEditor.FileSize());
1022 fBitmap = BTranslationUtils::GetBitmap(&stream);
1023 break;
1025 case B_MESSAGE_TYPE:
1027 BMessage message;
1028 // ToDo: this could be problematic if the data is not large
1029 // enough to contain the message...
1030 if (message.Unflatten(data) == B_OK)
1031 fBitmap = new BBitmap(&message);
1032 break;
1036 // Update the bitmap description. If no image can be displayed,
1037 // we will show our "unsupported" message
1039 if (fBitmap != NULL && fBitmap->InitCheck() != B_OK) {
1040 delete fBitmap;
1041 fBitmap = NULL;
1044 if (fBitmap != NULL) {
1045 char buffer[256];
1046 const char *type = B_TRANSLATE("Unknown type");
1047 switch (fEditor.Type()) {
1048 case B_MINI_ICON_TYPE:
1049 case B_LARGE_ICON_TYPE:
1050 #ifdef HAIKU_TARGET_PLATFORM_HAIKU
1051 case B_VECTOR_ICON_TYPE:
1052 #endif
1053 type = B_TRANSLATE("Icon");
1054 break;
1055 case B_PNG_FORMAT:
1056 type = B_TRANSLATE("PNG format");
1057 break;
1058 case B_MESSAGE_TYPE:
1059 type = B_TRANSLATE("Flattened bitmap");
1060 break;
1061 default:
1062 break;
1064 const char *colorSpace;
1065 switch (fBitmap->ColorSpace()) {
1066 case B_GRAY1:
1067 case B_GRAY8:
1068 colorSpace = B_TRANSLATE("Grayscale");
1069 break;
1070 case B_CMAP8:
1071 colorSpace = B_TRANSLATE("8 bit palette");
1072 break;
1073 case B_RGB32:
1074 case B_RGBA32:
1075 case B_RGB32_BIG:
1076 case B_RGBA32_BIG:
1077 colorSpace = B_TRANSLATE("32 bit");
1078 break;
1079 case B_RGB15:
1080 case B_RGBA15:
1081 case B_RGB15_BIG:
1082 case B_RGBA15_BIG:
1083 colorSpace = B_TRANSLATE("15 bit");
1084 break;
1085 case B_RGB16:
1086 case B_RGB16_BIG:
1087 colorSpace = B_TRANSLATE("16 bit");
1088 break;
1089 default:
1090 colorSpace = B_TRANSLATE("Unknown format");
1091 break;
1093 snprintf(buffer, sizeof(buffer), "%s, %g x %g, %s", type,
1094 fBitmap->Bounds().Width() + 1, fBitmap->Bounds().Height() + 1,
1095 colorSpace);
1096 fDescriptionView->SetText(buffer);
1097 } else
1098 fDescriptionView->SetText(B_TRANSLATE_COMMENT("Could not read image",
1099 "Image means here a picture file, not a disk image."));
1101 if (fBitmap != NULL) {
1102 if (fScaleSlider != NULL) {
1103 if (fScaleSlider->IsHidden())
1104 fScaleSlider->Show();
1106 } else if (fScaleSlider != NULL && !fScaleSlider->IsHidden())
1107 fScaleSlider->Hide();
1109 Invalidate();
1111 // restore old view size
1112 fEditor.SetViewSize(viewSize);
1116 // #pragma mark - MessageView
1119 MessageView::MessageView(BRect rect, DataEditor &editor)
1120 : TypeEditorView(rect, B_TRANSLATE("Message View"), B_FOLLOW_ALL, 0, editor)
1122 SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
1124 rect = Bounds().InsetByCopy(10, 10);
1125 rect.right -= B_V_SCROLL_BAR_WIDTH;
1126 rect.bottom -= B_H_SCROLL_BAR_HEIGHT;
1128 fTextView = new BTextView(rect, B_EMPTY_STRING,
1129 rect.OffsetToCopy(B_ORIGIN).InsetByCopy(5, 5),
1130 B_FOLLOW_ALL, B_WILL_DRAW);
1131 fTextView->SetViewUIColor(ViewUIColor());
1132 fTextView->SetLowUIColor(ViewUIColor());
1134 BScrollView *scrollView = new BScrollView("scroller", fTextView,
1135 B_FOLLOW_ALL, B_WILL_DRAW, true, true);
1136 AddChild(scrollView);
1140 MessageView::~MessageView()
1145 BString
1146 MessageView::_TypeToString(type_code type)
1148 // TODO: move this to a utility function (it's a copy from something
1149 // similar in ProbeView.cpp)
1150 char text[32];
1151 for (int32 i = 0; i < 4; i++) {
1152 text[i] = type >> (24 - 8 * i);
1153 if (text[i] < ' ' || text[i] == 0x7f) {
1154 snprintf(text, sizeof(text), "0x%04" B_PRIx32, type);
1155 break;
1156 } else if (i == 3)
1157 text[4] = '\0';
1160 return BString(text);
1164 void
1165 MessageView::SetTo(BMessage& message)
1167 // TODO: when we have a real column list/tree view, redo this using
1168 // it with nice editors as well.
1170 fTextView->SetText("");
1172 char text[512];
1173 snprintf(text, sizeof(text), B_TRANSLATE_COMMENT("what: '%.4s'\n\n",
1174 "'What' is a message specifier that defines the type of the message."),
1175 (char*)&message.what);
1176 fTextView->Insert(text);
1178 type_code type;
1179 int32 count;
1180 #ifdef HAIKU_TARGET_PLATFORM_DANO
1181 const
1182 #endif
1183 char* name;
1184 for (int32 i = 0; message.GetInfo(B_ANY_TYPE, i, &name, &type, &count)
1185 == B_OK; i++) {
1186 snprintf(text, sizeof(text), "%s\t", _TypeToString(type).String());
1187 fTextView->Insert(text);
1189 text_run_array array;
1190 array.count = 1;
1191 array.runs[0].offset = 0;
1192 array.runs[0].font.SetFace(B_BOLD_FACE);
1193 array.runs[0].color = (rgb_color){0, 0, 0, 255};
1195 fTextView->Insert(name, &array);
1197 array.runs[0].font = be_plain_font;
1198 fTextView->Insert("\n", &array);
1200 for (int32 j = 0; j < count; j++) {
1201 const char* data;
1202 ssize_t size;
1203 if (message.FindData(name, type, j, (const void**)&data, &size)
1204 != B_OK)
1205 continue;
1207 text[0] = '\0';
1209 switch (type) {
1210 case B_INT64_TYPE:
1211 snprintf(text, sizeof(text), "%" B_PRId64, *(int64*)data);
1212 break;
1213 case B_UINT64_TYPE:
1214 snprintf(text, sizeof(text), "%" B_PRIu64, *(uint64*)data);
1215 break;
1216 case B_INT32_TYPE:
1217 snprintf(text, sizeof(text), "%" B_PRId32, *(int32*)data);
1218 break;
1219 case B_UINT32_TYPE:
1220 snprintf(text, sizeof(text), "%" B_PRIu32, *(uint32*)data);
1221 break;
1222 case B_BOOL_TYPE:
1223 if (*(uint8*)data)
1224 strcpy(text, "true");
1225 else
1226 strcpy(text, "false");
1227 break;
1228 case B_STRING_TYPE:
1229 case B_MIME_STRING_TYPE:
1231 snprintf(text, sizeof(text), "%s", data);
1232 break;
1236 if (text[0]) {
1237 fTextView->Insert("\t\t");
1238 if (count > 1) {
1239 char index[16];
1240 snprintf(index, sizeof(index), "%" B_PRId32 ".\t", j);
1241 fTextView->Insert(index);
1243 fTextView->Insert(text);
1244 fTextView->Insert("\n");
1251 void
1252 MessageView::_UpdateMessage()
1254 BAutolock locker(fEditor);
1256 size_t viewSize = fEditor.ViewSize();
1257 // that may need some more memory...
1258 if ((off_t)viewSize < fEditor.FileSize())
1259 fEditor.SetViewSize(fEditor.FileSize());
1261 const char *buffer;
1262 if (fEditor.GetViewBuffer((const uint8 **)&buffer) == B_OK) {
1263 BMessage message;
1264 message.Unflatten(buffer);
1265 SetTo(message);
1268 // restore old view size
1269 fEditor.SetViewSize(viewSize);
1273 void
1274 MessageView::AttachedToWindow()
1276 fEditor.StartWatching(this);
1278 _UpdateMessage();
1282 void
1283 MessageView::DetachedFromWindow()
1285 fEditor.StopWatching(this);
1289 void
1290 MessageView::MessageReceived(BMessage* message)
1292 BView::MessageReceived(message);
1296 // #pragma mark -
1299 TypeEditorView*
1300 GetTypeEditorFor(BRect rect, DataEditor& editor)
1302 switch (editor.Type()) {
1303 case B_STRING_TYPE:
1304 return new StringEditor(editor);
1305 case B_MIME_STRING_TYPE:
1306 return new MimeTypeEditor(rect, editor);
1307 case B_BOOL_TYPE:
1308 return new BooleanEditor(rect, editor);
1309 case B_INT8_TYPE:
1310 case B_UINT8_TYPE:
1311 case B_INT16_TYPE:
1312 case B_UINT16_TYPE:
1313 case B_INT32_TYPE:
1314 case B_UINT32_TYPE:
1315 case B_INT64_TYPE:
1316 case B_UINT64_TYPE:
1317 case B_FLOAT_TYPE:
1318 case B_DOUBLE_TYPE:
1319 case B_SSIZE_T_TYPE:
1320 case B_SIZE_T_TYPE:
1321 case B_OFF_T_TYPE:
1322 case B_POINTER_TYPE:
1323 return new NumberEditor(rect, editor);
1324 case B_MESSAGE_TYPE:
1325 // TODO: check for archived bitmaps!!!
1326 return new MessageView(rect, editor);
1327 case B_MINI_ICON_TYPE:
1328 case B_LARGE_ICON_TYPE:
1329 case B_PNG_FORMAT:
1330 #ifdef HAIKU_TARGET_PLATFORM_HAIKU
1331 case B_VECTOR_ICON_TYPE:
1332 #endif
1333 return new ImageView(editor);
1336 return NULL;
1340 status_t
1341 GetNthTypeEditor(int32 index, const char** _name)
1343 static const char* kEditors[] = {
1344 B_TRANSLATE_COMMENT("Text", "This is the type of editor"),
1345 B_TRANSLATE_COMMENT("Number", "This is the type of editor"),
1346 B_TRANSLATE_COMMENT("Boolean", "This is the type of editor"),
1347 B_TRANSLATE_COMMENT("Message", "This is the type of view"),
1348 B_TRANSLATE_COMMENT("Image", "This is the type of view")
1351 if (index < 0 || index >= int32(sizeof(kEditors) / sizeof(kEditors[0])))
1352 return B_BAD_VALUE;
1354 *_name = kEditors[index];
1355 return B_OK;
1359 TypeEditorView*
1360 GetTypeEditorAt(int32 index, BRect rect, DataEditor& editor)
1362 TypeEditorView* view = NULL;
1364 switch (index) {
1365 case 0:
1366 view = new StringEditor(editor);
1367 break;
1368 case 1:
1369 view = new NumberEditor(rect, editor);
1370 break;
1371 case 2:
1372 view = new BooleanEditor(rect, editor);
1373 break;
1374 case 3:
1375 view = new MessageView(rect, editor);
1376 break;
1377 case 4:
1378 view = new ImageView(editor);
1379 break;
1381 default:
1382 return NULL;
1385 if (view == NULL)
1386 return NULL;
1388 if (!view->TypeMatches()) {
1389 delete view;
1390 return NULL;
1393 return view;