1 /* 2 * Copyright 2014-2023 Haiku, Inc. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Zhuowei Zhang 7 * Humdinger 8 */ 9 #include "ConsoleWindow.h" 10 11 #include <Catalog.h> 12 #include <Clipboard.h> 13 #include <Message.h> 14 #include <Button.h> 15 #include <GroupLayout.h> 16 #include <GroupLayoutBuilder.h> 17 #include <LayoutBuilder.h> 18 #include <SeparatorView.h> 19 #include <StringFormat.h> 20 #include <TextControl.h> 21 #include <ListView.h> 22 #include <ScrollView.h> 23 24 #include "BrowserWindow.h" 25 #include "BrowserApp.h" 26 #include "WebViewConstants.h" 27 28 29 #undef B_TRANSLATION_CONTEXT 30 #define B_TRANSLATION_CONTEXT "Console Window" 31 32 33 enum { 34 EVAL_CONSOLE_WINDOW_COMMAND = 'ecwc', 35 CLEAR_CONSOLE_MESSAGES = 'ccms' 36 }; 37 38 39 ConsoleWindow::ConsoleWindow(BRect frame) 40 : 41 BWindow(frame, B_TRANSLATE("Script console"), B_TITLED_WINDOW, 42 B_NORMAL_WINDOW_FEEL, B_AUTO_UPDATE_SIZE_LIMITS 43 | B_ASYNCHRONOUS_CONTROLS | B_NOT_ZOOMABLE), 44 fPreviousText(""), 45 fRepeatCounter(0) 46 { 47 SetLayout(new BGroupLayout(B_VERTICAL, 0.0)); 48 49 fMessagesListView = new BListView("Console messages", 50 B_MULTIPLE_SELECTION_LIST); 51 52 fClearMessagesButton = new BButton(B_TRANSLATE("Clear"), 53 new BMessage(CLEAR_CONSOLE_MESSAGES)); 54 fCopyMessagesButton = new BButton(B_TRANSLATE("Copy"), 55 new BMessage(B_COPY)); 56 57 AddChild(BGroupLayoutBuilder(B_VERTICAL, 0.0) 58 .Add(new BScrollView("Console messages scroll", 59 fMessagesListView, 0, true, true)) 60 .Add(BGroupLayoutBuilder(B_HORIZONTAL, B_USE_SMALL_SPACING) 61 .AddGlue() 62 .Add(fClearMessagesButton) 63 .Add(fCopyMessagesButton) 64 .AddGlue() 65 .SetInsets(0, B_USE_SMALL_SPACING, 0, 0)) 66 .SetInsets(B_USE_SMALL_SPACING, B_USE_SMALL_SPACING, 67 B_USE_SMALL_SPACING, B_USE_SMALL_SPACING) 68 ); 69 if (!frame.IsValid()) 70 CenterOnScreen(); 71 } 72 73 74 void 75 ConsoleWindow::MessageReceived(BMessage* message) 76 { 77 switch (message->what) { 78 case ADD_CONSOLE_MESSAGE: 79 { 80 BString source = message->FindString("source"); 81 int32 lineNumber = message->FindInt32("line"); 82 int32 columnNumber = message->FindInt32("column"); 83 BString text = message->FindString("string"); 84 BString finalText; 85 finalText.SetToFormat("%s:%" B_PRIi32 ":%" B_PRIi32 ": %s\n", 86 source.String(), lineNumber, columnNumber, text.String()); 87 88 if (finalText == fPreviousText) { 89 finalText = ""; 90 static BStringFormat format(B_TRANSLATE("{0, plural," 91 "one{Last line repeated # time.}" 92 "other{Last line repeated # times.}}")); 93 format.Format(finalText, ++fRepeatCounter); 94 // preserve the repeated line 95 if (fRepeatCounter > 1) { 96 int32 index = fMessagesListView->CountItems() - 1; 97 BStringItem* item = (BStringItem*)fMessagesListView->ItemAt(index); 98 item->SetText(finalText.String()); 99 fMessagesListView->InvalidateItem(index); 100 break; 101 } 102 } else { 103 fPreviousText = finalText; 104 fRepeatCounter = 0; 105 } 106 fMessagesListView->AddItem(new BStringItem(finalText.String())); 107 break; 108 } 109 case CLEAR_CONSOLE_MESSAGES: 110 { 111 fPreviousText = ""; 112 int count = fMessagesListView->CountItems(); 113 for (int i = count - 1; i >= 0; i--) 114 delete fMessagesListView->RemoveItem(i); 115 break; 116 } 117 case B_COPY: 118 { 119 _CopyToClipboard(); 120 break; 121 } 122 default: 123 BWindow::MessageReceived(message); 124 break; 125 } 126 } 127 128 129 bool 130 ConsoleWindow::QuitRequested() 131 { 132 if (!IsHidden()) 133 Hide(); 134 return false; 135 } 136 137 138 void 139 ConsoleWindow::_CopyToClipboard() 140 { 141 BString text; 142 int32 index; 143 if (fMessagesListView->CurrentSelection() == -1) { 144 for (int32 i = 0; i < fMessagesListView->CountItems(); i++) { 145 BStringItem* item = (BStringItem*)fMessagesListView->ItemAt(i); 146 text << item->Text(); 147 } 148 } else { 149 for (int32 i = 0; (index = fMessagesListView->CurrentSelection(i)) >= 0; i++) { 150 BStringItem* item = (BStringItem*)fMessagesListView->ItemAt(index); 151 text << item->Text(); 152 } 153 } 154 155 ssize_t textLen = text.Length(); 156 if (be_clipboard->Lock()) { 157 be_clipboard->Clear(); 158 BMessage* clip = be_clipboard->Data(); 159 if (clip != NULL) { 160 clip->AddData("text/plain", B_MIME_TYPE, text.String(), textLen); 161 be_clipboard->Commit(); 162 } 163 be_clipboard->Unlock(); 164 } 165 } 166