btrfs: Attempt to fix GCC2 build.
[haiku.git] / src / apps / diskprobe / FindWindow.cpp
blob1e7d53fe00b884ae20d5b0a2a1e8737a4cc2c7fe
1 /*
2 * Copyright 2004-2009, Axel Dörfler, axeld@pinc-software.de.
3 * Copyright 2009, Philippe St-Pierre, stpere@gmail.com
4 * Distributed under the terms of the MIT License.
5 */
8 #include "FindWindow.h"
10 #include <stdlib.h>
11 #include <stdio.h>
12 #include <string.h>
14 #include <Application.h>
15 #include <Autolock.h>
16 #include <AutoLocker.h>
17 #include <Beep.h>
18 #include <Button.h>
19 #include <Catalog.h>
20 #include <CheckBox.h>
21 #include <Clipboard.h>
22 #include <Locale.h>
23 #include <MenuField.h>
24 #include <MenuItem.h>
25 #include <Mime.h>
26 #include <PopUpMenu.h>
27 #include <ScrollView.h>
28 #include <TextView.h>
30 #include "DataView.h"
31 #include "DiskProbe.h"
34 #undef B_TRANSLATION_CONTEXT
35 #define B_TRANSLATION_CONTEXT "FindWindow"
37 static const uint32 kMsgFindMode = 'FMde';
38 static const uint32 kMsgStartFind = 'SFnd';
41 class FindTextView : public BTextView {
42 public:
43 FindTextView(BRect frame, const char* name,
44 BRect textRect, uint32 resizeMask);
46 virtual void MakeFocus(bool state);
47 virtual void TargetedByScrollView(BScrollView* view);
49 find_mode Mode() const { return fMode; }
50 status_t SetMode(find_mode mode);
52 void SetData(BMessage& message);
53 void GetData(BMessage& message);
55 virtual void KeyDown(const char* bytes, int32 numBytes);
57 virtual bool AcceptsPaste(BClipboard* clipboard);
58 virtual void Copy(BClipboard* clipboard);
59 virtual void Cut(BClipboard* clipboard);
60 virtual void Paste(BClipboard* clipboard);
62 protected:
63 virtual void InsertText(const char* text, int32 length,
64 int32 offset, const text_run_array* runs);
66 private:
67 void _HexReformat(int32 oldCursor, int32& newCursor);
68 status_t _GetHexFromData(const uint8* in, size_t inSize,
69 char** _hex, size_t* _hexSize);
70 status_t _GetDataFromHex(const char* text, size_t textLength,
71 uint8** _data, size_t* _dataSize);
73 BScrollView* fScrollView;
74 find_mode fMode;
78 FindTextView::FindTextView(BRect frame, const char* name, BRect textRect,
79 uint32 resizeMask)
80 : BTextView(frame, name, textRect, resizeMask),
81 fScrollView(NULL),
82 fMode(kAsciiMode)
87 void
88 FindTextView::MakeFocus(bool state)
90 BTextView::MakeFocus(state);
92 if (fScrollView != NULL)
93 fScrollView->SetBorderHighlighted(state);
97 void
98 FindTextView::TargetedByScrollView(BScrollView* view)
100 BTextView::TargetedByScrollView(view);
101 fScrollView = view;
105 void
106 FindTextView::_HexReformat(int32 oldCursor, int32& newCursor)
108 const char* text = Text();
109 int32 textLength = TextLength();
110 char* insert = (char*)malloc(textLength * 2);
111 if (insert == NULL)
112 return;
114 newCursor = TextLength();
115 int32 out = 0;
116 for (int32 i = 0; i < textLength; i++) {
117 if (i == oldCursor) {
118 // this is the end of the inserted text
119 newCursor = out;
122 char c = text[i];
123 if (c >= 'A' && c <= 'F')
124 c += 'a' - 'A';
125 if ((c >= 'a' && c <= 'f') || (c >= '0' && c <= '9'))
126 insert[out++] = c;
128 if ((out % 48) == 47)
129 insert[out++] = '\n';
130 else if ((out % 3) == 2)
131 insert[out++] = ' ';
133 insert[out] = '\0';
135 DeleteText(0, textLength);
137 // InsertText() does not work here, as we need the text
138 // to be reformatted as well (newlines, breaks, whatever).
139 // IOW the BTextView class is not very nicely done.
140 // BTextView::InsertText(insert, out, 0, NULL);
141 fMode = kAsciiMode;
142 Insert(0, insert, out);
143 fMode = kHexMode;
145 free(insert);
149 void
150 FindTextView::InsertText(const char* text, int32 length, int32 offset,
151 const text_run_array* runs)
153 if (fMode == kHexMode) {
154 if (offset > TextLength())
155 offset = TextLength();
157 BTextView::InsertText(text, length, offset, runs);
158 // lets add anything, and then start to filter out
159 // (since we have to reformat the whole text)
161 int32 start, end;
162 GetSelection(&start, &end);
164 int32 cursor;
165 _HexReformat(offset, cursor);
167 if (length == 1 && start == offset)
168 Select(cursor + 1, cursor + 1);
169 } else
170 BTextView::InsertText(text, length, offset, runs);
174 void
175 FindTextView::KeyDown(const char* bytes, int32 numBytes)
177 if (fMode == kHexMode) {
178 // filter out invalid (for hex mode) characters
179 if (numBytes > 1)
180 return;
182 switch (bytes[0]) {
183 case B_RIGHT_ARROW:
184 case B_LEFT_ARROW:
185 case B_UP_ARROW:
186 case B_DOWN_ARROW:
187 case B_HOME:
188 case B_END:
189 case B_PAGE_UP:
190 case B_PAGE_DOWN:
191 break;
193 case B_BACKSPACE:
194 case B_DELETE:
196 int32 start, end;
197 GetSelection(&start, &end);
199 if (bytes[0] == B_BACKSPACE && --start < 0) {
200 if (end == 0)
201 return;
202 start = 0;
205 if (ByteAt(start) == ' ')
206 BTextView::KeyDown(bytes, numBytes);
208 BTextView::KeyDown(bytes, numBytes);
210 if (bytes[0] == B_BACKSPACE)
211 GetSelection(&start, &end);
213 _HexReformat(start, start);
214 Select(start, start);
215 return;
218 default:
220 if (!strchr("0123456789abcdefABCDEF", bytes[0]))
221 return;
223 // the original KeyDown() has severe cursor setting
224 // problems with our InsertText().
226 int32 start, end;
227 GetSelection(&start, &end);
228 InsertText(bytes, 1, start, NULL);
229 return;
233 BTextView::KeyDown(bytes, numBytes);
237 bool
238 FindTextView::AcceptsPaste(BClipboard* clipboard)
240 if (clipboard == NULL)
241 return false;
243 AutoLocker<BClipboard> _(clipboard);
245 BMessage* clip = clipboard->Data();
246 if (clip == NULL)
247 return false;
249 if (clip->HasData(B_FILE_MIME_TYPE, B_MIME_TYPE)
250 || clip->HasData("text/plain", B_MIME_TYPE))
251 return true;
253 return BTextView::AcceptsPaste(clipboard);
257 void
258 FindTextView::Copy(BClipboard* clipboard)
260 if (fMode != kHexMode) {
261 BTextView::Copy(clipboard);
262 return;
265 int32 start, end;
266 GetSelection(&start, &end);
268 if (clipboard == NULL || start == end)
269 return;
271 AutoLocker<BClipboard> _(clipboard);
273 BMessage* clip = clipboard->Data();
274 if (clip == NULL)
275 return;
277 // convert hex-text to real data
278 uint8* data;
279 size_t dataSize;
280 if (_GetDataFromHex(Text() + start, end - start, &data, &dataSize)
281 != B_OK)
282 return;
284 clip->AddData(B_FILE_MIME_TYPE, B_MIME_TYPE, data, dataSize);
286 if (is_valid_utf8(data, dataSize))
287 clip->AddData("text/plain", B_MIME_TYPE, data, dataSize);
289 free(data);
293 void
294 FindTextView::Cut(BClipboard* clipboard)
296 if (fMode != kHexMode) {
297 BTextView::Cut(clipboard);
298 return;
301 int32 start, end;
302 GetSelection(&start, &end);
303 if (clipboard == NULL || start == end)
304 return;
306 AutoLocker<BClipboard> _(clipboard);
308 BMessage* clip = clipboard->Data();
309 if (clip == NULL)
310 return;
312 Copy(clipboard);
313 Clear();
317 void
318 FindTextView::Paste(BClipboard* clipboard)
320 if (clipboard == NULL)
321 return;
323 AutoLocker<BClipboard> _(clipboard);
325 BMessage* clip = clipboard->Data();
326 if (clip == NULL)
327 return;
329 const uint8* data;
330 ssize_t dataSize;
331 if (clip->FindData(B_FILE_MIME_TYPE, B_MIME_TYPE, (const void**)&data,
332 &dataSize) == B_OK) {
333 if (fMode == kHexMode) {
334 char* hex;
335 size_t hexSize;
336 if (_GetHexFromData(data, dataSize, &hex, &hexSize) < B_OK)
337 return;
339 Insert(hex, hexSize);
340 free(hex);
341 } else
342 Insert((char*)data, dataSize);
343 return;
346 BTextView::Paste(clipboard);
350 status_t
351 FindTextView::_GetHexFromData(const uint8* in, size_t inSize, char** _hex,
352 size_t* _hexSize)
354 char* hex = (char*)malloc(inSize * 3 + 1);
355 if (hex == NULL)
356 return B_NO_MEMORY;
358 char* out = hex;
359 for (uint32 i = 0; i < inSize; i++) {
360 out += sprintf(out, "%02x", *(unsigned char*)(in + i));
362 out[0] = '\0';
364 *_hex = hex;
365 *_hexSize = out + 1 - hex;
366 return B_OK;
370 status_t
371 FindTextView::_GetDataFromHex(const char* text, size_t textLength, uint8** _data,
372 size_t* _dataSize)
374 uint8* data = (uint8*)malloc(textLength);
375 if (data == NULL)
376 return B_NO_MEMORY;
378 size_t dataSize = 0;
379 uint8 hiByte = 0;
380 bool odd = false;
381 for (uint32 i = 0; i < textLength; i++) {
382 char c = text[i];
383 int32 number;
384 if (c >= 'A' && c <= 'F')
385 number = c + 10 - 'A';
386 else if (c >= 'a' && c <= 'f')
387 number = c + 10 - 'a';
388 else if (c >= '0' && c <= '9')
389 number = c - '0';
390 else
391 continue;
393 if (!odd)
394 hiByte = (number << 4) & 0xf0;
395 else
396 data[dataSize++] = hiByte | (number & 0x0f);
398 odd = !odd;
400 if (odd)
401 data[dataSize++] = hiByte;
403 *_data = data;
404 *_dataSize = dataSize;
405 return B_OK;
409 status_t
410 FindTextView::SetMode(find_mode mode)
412 if (fMode == mode)
413 return B_OK;
415 if (mode == kHexMode) {
416 // convert text to hex mode
418 char* hex;
419 size_t hexSize;
420 if (_GetHexFromData((const uint8*)Text(), TextLength(), &hex, &hexSize)
421 < B_OK)
422 return B_NO_MEMORY;
424 fMode = mode;
426 SetText(hex, hexSize);
427 free(hex);
428 } else {
429 // convert hex to ascii
431 uint8* data;
432 size_t dataSize;
433 if (_GetDataFromHex(Text(), TextLength(), &data, &dataSize) < B_OK)
434 return B_NO_MEMORY;
436 fMode = mode;
438 SetText((const char*)data, dataSize);
439 free(data);
442 return B_OK;
446 void
447 FindTextView::SetData(BMessage& message)
449 const uint8* data;
450 ssize_t dataSize;
451 if (message.FindData("data", B_RAW_TYPE,
452 (const void**)&data, &dataSize) != B_OK)
453 return;
455 if (fMode == kHexMode) {
456 char* hex;
457 size_t hexSize;
458 if (_GetHexFromData(data, dataSize, &hex, &hexSize) < B_OK)
459 return;
461 SetText(hex, hexSize);
462 free(hex);
463 } else
464 SetText((char*)data, dataSize);
468 void
469 FindTextView::GetData(BMessage& message)
471 if (fMode == kHexMode) {
472 // convert hex-text to real data
473 uint8* data;
474 size_t dataSize;
475 if (_GetDataFromHex(Text(), TextLength(), &data, &dataSize) != B_OK)
476 return;
478 message.AddData("data", B_RAW_TYPE, data, dataSize);
479 free(data);
480 } else
481 message.AddData("data", B_RAW_TYPE, Text(), TextLength());
485 // #pragma mark -
488 FindWindow::FindWindow(BRect _rect, BMessage& previous, BMessenger& target,
489 const BMessage* settings)
490 : BWindow(_rect, B_TRANSLATE("Find"), B_TITLED_WINDOW,
491 B_ASYNCHRONOUS_CONTROLS | B_CLOSE_ON_ESCAPE),
492 fTarget(target)
494 BView* view = new BView(Bounds(), "main", B_FOLLOW_ALL, 0);
495 view->SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
496 AddChild(view);
498 int8 mode = kAsciiMode;
499 if (previous.FindInt8("find_mode", &mode) != B_OK && settings != NULL)
500 settings->FindInt8("find_mode", &mode);
502 // add the top widgets
504 fMenu = new BPopUpMenu("mode");
505 BMessage* message;
506 BMenuItem* item;
507 fMenu->AddItem(item = new BMenuItem(B_TRANSLATE("Text"),
508 message = new BMessage(kMsgFindMode)));
509 message->AddInt8("mode", kAsciiMode);
510 if (mode == kAsciiMode)
511 item->SetMarked(true);
512 fMenu->AddItem(item = new BMenuItem(B_TRANSLATE_COMMENT("Hexadecimal",
513 "A menu item, as short as possible, noun is recommended if it is "
514 "shorter than adjective."), message = new BMessage(kMsgFindMode)));
515 message->AddInt8("mode", kHexMode);
516 if (mode == kHexMode)
517 item->SetMarked(true);
519 BRect rect = Bounds().InsetByCopy(5, 5);
520 BMenuField* menuField = new BMenuField(rect, B_EMPTY_STRING,
521 B_TRANSLATE("Mode:"), fMenu, B_FOLLOW_LEFT | B_FOLLOW_TOP);
522 menuField->SetDivider(menuField->StringWidth(menuField->Label()) + 8);
523 menuField->ResizeToPreferred();
524 view->AddChild(menuField);
526 // add the bottom widgets
528 BButton* button = new BButton(rect, B_EMPTY_STRING, B_TRANSLATE("Find"),
529 new BMessage(kMsgStartFind), B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM);
530 button->MakeDefault(true);
531 button->ResizeToPreferred();
532 button->MoveTo(rect.right - button->Bounds().Width(),
533 rect.bottom - button->Bounds().Height());
534 view->AddChild(button);
536 fCaseCheckBox = new BCheckBox(rect, B_EMPTY_STRING, B_TRANSLATE("Case sensitive"),
537 NULL, B_FOLLOW_LEFT | B_FOLLOW_BOTTOM);
538 fCaseCheckBox->ResizeToPreferred();
539 fCaseCheckBox->MoveTo(5, button->Frame().top);
540 bool caseSensitive;
541 if (previous.FindBool("case_sensitive", &caseSensitive) != B_OK) {
542 if (settings == NULL
543 || settings->FindBool("case_sensitive", &caseSensitive) != B_OK)
544 caseSensitive = true;
546 fCaseCheckBox->SetValue(caseSensitive);
547 view->AddChild(fCaseCheckBox);
549 // and now those inbetween
551 rect.top = menuField->Frame().bottom + 5;
552 rect.bottom = fCaseCheckBox->Frame().top - 8;
553 rect.InsetBy(2, 2);
554 fTextView = new FindTextView(rect, B_EMPTY_STRING,
555 rect.OffsetToCopy(B_ORIGIN).InsetByCopy(3, 3), B_FOLLOW_ALL);
556 fTextView->SetWordWrap(true);
557 fTextView->SetMode((find_mode)mode);
558 fTextView->SetData(previous);
560 BScrollView* scrollView = new BScrollView("scroller", fTextView,
561 B_FOLLOW_ALL, B_WILL_DRAW, false, false);
562 view->AddChild(scrollView);
564 ResizeTo(290, button->Frame().Height() * 3 + 30);
566 SetSizeLimits(fCaseCheckBox->Bounds().Width() + button->Bounds().Width()
567 + 20, 32768, button->Frame().Height() * 3 + 10, 32768);
571 FindWindow::~FindWindow()
576 void
577 FindWindow::WindowActivated(bool active)
579 fTextView->MakeFocus(active);
583 void
584 FindWindow::MessageReceived(BMessage* message)
586 switch (message->what) {
587 case kMsgFindMode:
589 int8 mode;
590 if (message->FindInt8("mode", &mode) != B_OK)
591 break;
593 if (fTextView->SetMode((find_mode)mode) != B_OK) {
594 // activate other item
595 fMenu->ItemAt(mode == kAsciiMode ? 1 : 0)->SetMarked(true);
596 beep();
598 fTextView->MakeFocus(true);
599 break;
602 case kMsgStartFind:
604 BMessage find(kMsgFind);
605 fTextView->GetData(find);
606 find.AddBool("case_sensitive", fCaseCheckBox->Value() != 0);
607 find.AddInt8("find_mode", fTextView->Mode());
608 fTarget.SendMessage(&find);
610 PostMessage(B_QUIT_REQUESTED);
611 break;
614 default:
615 BWindow::MessageReceived(message);
620 bool
621 FindWindow::QuitRequested()
623 // update the application's settings
624 BMessage update(kMsgSettingsChanged);
625 update.AddBool("case_sensitive", fCaseCheckBox->Value() != 0);
626 update.AddInt8("find_mode", fTextView->Mode());
627 be_app_messenger.SendMessage(&update);
629 be_app_messenger.SendMessage(kMsgFindWindowClosed);
630 return true;
634 void
635 FindWindow::Show()
637 fTextView->SelectAll();
638 BWindow::Show();
642 void
643 FindWindow::SetTarget(BMessenger& target)
645 fTarget = target;