blob: fc2970821b1ecaa8a0e65e0a0d1d94e3b8d627ce [file] [log] [blame]
PulkoMandy69eec3e2023-04-10 15:22:28 +02001/*
2 * Copyright (C) 2023 Adrien Destugues <pulkomandy@pulkomandy.tk>
3 *
4 * Distributed under terms of the MIT license.
5 */
6
PulkoMandyee68b1e2023-04-21 22:54:09 +02007#include <private/interface/AboutWindow.h>
PulkoMandy69eec3e2023-04-10 15:22:28 +02008#include <Application.h>
9#include <private/interface/ColumnListView.h>
10#include <private/interface/ColumnTypes.h>
11#include <GroupLayout.h>
12#include <LayoutBuilder.h>
13#include <MenuBar.h>
14#include <Window.h>
15
16#include <ctype.h>
17
18#include "../BeDC.h"
19
20
21class BColorStringField: public BStringField
22{
23public:
24 BColorStringField(const char* string, rgb_color color)
25 : BStringField(string)
26 , fColor(color)
27 {
28 }
29
30 rgb_color fColor;
31};
32
33
34class BColorStringColumn: public BStringColumn
35{
36public:
37 BColorStringColumn(const char* title, float w, float minw, float maxw)
38 : BStringColumn(title, w, minw, maxw, false)
39 {
40 }
41
42 void DrawField(BField* field, BRect rect, BView* parent) override
43 {
44 BColorStringField* csField = dynamic_cast<BColorStringField*>(field);
45 if (csField) {
46 parent->SetHighColor(csField->fColor);
47 }
48 BStringColumn::DrawField(field, rect, parent);
49 }
50};
51
52
53static char sanechar(int32 input) {
54 input = input & 0xff;
55 if (isprint(input))
56 return (char)input;
57 else
58 return '.';
59}
60
61
62class LoggerWindow: public BWindow
63{
64public:
65 LoggerWindow()
66 : BWindow(BRect(100, 100, 900, 700), "Dev console", B_DOCUMENT_WINDOW,
67 B_QUIT_ON_WINDOW_CLOSE | B_AUTO_UPDATE_SIZE_LIMITS)
68 {
69 BGroupLayout* layout = new BGroupLayout(B_VERTICAL);
70 SetLayout(layout);
71 layout->SetSpacing(0);
72
73 fEventList = new BColumnListView("messages", 0, B_NO_BORDER);
74 fEventList->AddColumn(new BColorStringColumn("Name", 100, 50, 200), 0);
75 fEventList->AddColumn(new BColorStringColumn("Text", INT16_MAX, 50, INT16_MAX), 1);
76
PulkoMandyee68b1e2023-04-21 22:54:09 +020077 BMenuBar* mainMenu = new BMenuBar("main menu");
78
79 BMessage* separatorMessage = new BMessage(BEDC_MESSAGE);
80 separatorMessage->AddInt8("bedc_type", DC_SEPARATOR);
81
82 BMessage* clearMessage = new BMessage(BEDC_MESSAGE);
83 clearMessage->AddInt8("bedc_type", DC_CLEAR);
84
85 BLayoutBuilder::Menu<>(mainMenu)
86 .AddMenu("File")
87 .AddItem("New window", new BMessage(), 'N')
88 .AddItem("Activate window", new BMessage(), 'S')
89 .SetEnabled(false)
90 .AddSeparator()
91 .AddItem("About…", new BMessage(B_ABOUT_REQUESTED))
92 .AddSeparator()
93 .AddItem("Quit", new BMessage(B_QUIT_REQUESTED), 'Q')
94 .End()
95 .AddMenu("Edit")
96 .AddItem("Cut", new BMessage(), 'X')
97 .AddItem("Copy", new BMessage(), 'C')
98 .AddItem("Delete", new BMessage(), 'D')
99 .AddSeparator()
100 .AddItem("Clear", clearMessage, 'E')
101 .AddItem("Select all", new BMessage(), 'A')
102 .AddSeparator()
103 .AddItem("Preferences", new BMessage())
104 .End()
105 .AddMenu("Tools")
106 .AddItem("Add separator", separatorMessage, 'S')
107 .AddSeparator()
108 .AddItem("Save to file…", new BMessage())
109 .AddItem("Save selection to file…", new BMessage())
110 .End()
111 .End();
112
PulkoMandy69eec3e2023-04-10 15:22:28 +0200113 BLayoutBuilder::Group<>(layout)
114 .SetInsets(0, -1, -1, -1)
PulkoMandyee68b1e2023-04-21 22:54:09 +0200115 .Add(mainMenu)
PulkoMandy69eec3e2023-04-10 15:22:28 +0200116 .Add(fEventList)
117 .End();
PulkoMandyee68b1e2023-04-21 22:54:09 +0200118
119 // TODO make all menu items work
120 // TODO add status bar with online/offline status and line counter
121 // Newest created window becomes active, deactivates all other
122 // Actve window can be switched from menu
123 // Active window has its 'activate window' menu disabled, using the shortcut adds a
124 // separator instead
125 // TODO add line numbers in list view
PulkoMandy69eec3e2023-04-10 15:22:28 +0200126 }
127
128 void MessageReceived(BMessage* message) override
129 {
130 switch(message->what) {
131 case BEDC_MESSAGE:
132 {
PulkoMandyee68b1e2023-04-21 22:54:09 +0200133 // TODO parse bedc_ver to handle mulitple protocol versions
PulkoMandy69eec3e2023-04-10 15:22:28 +0200134 BString name = message->FindString("bedc_name");
135 BString text = message->FindString("bedc_text");
136 int8 colorEnum = message->FindInt8("bedc_color");
137 int8 type = message->FindInt8("bedc_type");
138 int8 main_type = message->FindInt8("bedc_main_type");
139
140 if (type == DC_CLEAR) {
141 fEventList->Clear();
142 return;
143 }
144
145 if (main_type == BEDC_BMESSAGE && text.IsEmpty()) {
146 int32 what = message->FindInt32("bedc_what");
PulkoMandyee68b1e2023-04-21 22:54:09 +0200147 BString description = message->FindString("bedc_desc");
148 if (description.IsEmpty())
149 description = "BMessage";
PulkoMandy69eec3e2023-04-10 15:22:28 +0200150
PulkoMandyee68b1e2023-04-21 22:54:09 +0200151 text.SetToFormat("%s(what=%#010x, %d, '%c%c%c%c')", description.String(),
152 what, what,
PulkoMandy69eec3e2023-04-10 15:22:28 +0200153 sanechar(what >> 24), sanechar(what >> 16),
154 sanechar(what >> 8), sanechar(what >> 0));
155 }
156
PulkoMandy69eec3e2023-04-10 15:22:28 +0200157 BRow* row = new BRow();
158 if (colorEnum == 0) {
159 row->SetField(new BStringField(name), 0);
160 } else {
161 rgb_color color;
162 switch(colorEnum) {
163 case DC_WHITE:
164 color = make_color(128, 128, 128, 255);
165 break;
166 case DC_BLACK:
167 color = make_color(64, 64, 64, 255);
168 break;
169 case DC_BLUE:
170 color = make_color(0, 0, 128, 255);
171 break;
172 case DC_RED:
173 color = make_color(0, 128, 0, 255);
174 break;
175 case DC_YELLOW:
176 color = make_color(128, 128, 0, 255);
177 break;
178 case DC_GREEN:
179 color = make_color(128, 0, 0, 255);
180 break;
181 }
182 row->SetField(new BColorStringField(name, color), 0);
183 }
184
185 if (type == DC_SUCCESS)
186 row->SetField(new BColorStringField(text, ui_color(B_SUCCESS_COLOR)), 1);
187 else if (type == DC_ERROR)
188 row->SetField(new BColorStringField(text, ui_color(B_FAILURE_COLOR)), 1);
189 else if (type == DC_MESSAGE)
190 row->SetField(new BStringField(text), 1);
191 else if (type == DC_SEPARATOR)
192 row->SetField(new BStringField("-----"), 1);
193 else {
194 message->PrintToStream();
195 }
196 fEventList->AddRow(row, -1);
197
PulkoMandyee68b1e2023-04-21 22:54:09 +0200198 // For BEDC_MESSAGE, there is no bedc_text, but instead all non-bedc fields of the
199 // message should be added to the view. We add them in subrows that can be folded.
PulkoMandy69eec3e2023-04-10 15:22:28 +0200200 if (main_type == BEDC_BMESSAGE) {
201 int index = 0;
202 char* nameFound;
203 type_code typeFound;
204 int32 countFound;
205 while (message->GetInfo(B_ANY_TYPE, index++, &nameFound, &typeFound, &countFound) == B_OK) {
206 // Don't display all the bedc_ internal stuff
207 if (BString(nameFound).StartsWith("bedc_"))
208 continue;
209
210 for (int j = 0; j < countFound; j++) {
211 name.SetToFormat("%s[%d] (%c%c%c%c)", nameFound, j,
212 (typeFound >> 24) & 0xFF, (typeFound >> 16) & 0xFF,
213 (typeFound >> 8) & 0xFF, (typeFound >> 0) & 0xFF
214 );
215
216 switch(typeFound) {
217#if 0
218 B_AFFINE_TRANSFORM_TYPE = 'AMTX',
219 B_ALIGNMENT_TYPE = 'ALGN',
220 B_ANY_TYPE = 'ANYT',
221 B_ATOM_TYPE = 'ATOM',
222 B_ATOMREF_TYPE = 'ATMR',
223 B_BOOL_TYPE = 'BOOL',
224 B_CHAR_TYPE = 'CHAR',
225 B_COLOR_8_BIT_TYPE = 'CLRB',
226 B_DOUBLE_TYPE = 'DBLE',
227 B_FLOAT_TYPE = 'FLOT',
228 B_GRAYSCALE_8_BIT_TYPE = 'GRYB',
229 B_INT16_TYPE = 'SHRT',
230 B_INT64_TYPE = 'LLNG',
231 B_INT8_TYPE = 'BYTE',
232 B_LARGE_ICON_TYPE = 'ICON',
233 B_MEDIA_PARAMETER_GROUP_TYPE = 'BMCG',
234 B_MEDIA_PARAMETER_TYPE = 'BMCT',
235 B_MEDIA_PARAMETER_WEB_TYPE = 'BMCW',
236 B_MESSAGE_TYPE = 'MSGG',
237 B_MESSENGER_TYPE = 'MSNG',
238 B_MIME_TYPE = 'MIME',
239 B_MINI_ICON_TYPE = 'MICN',
240 B_MONOCHROME_1_BIT_TYPE = 'MNOB',
241 B_OBJECT_TYPE = 'OPTR',
242 B_OFF_T_TYPE = 'OFFT',
243 B_PATTERN_TYPE = 'PATN',
244 B_POINTER_TYPE = 'PNTR',
245 B_PROPERTY_INFO_TYPE = 'SCTD',
246 B_RAW_TYPE = 'RAWT',
247 B_RECT_TYPE = 'RECT',
248 B_REF_TYPE = 'RREF',
249 B_NODE_REF_TYPE = 'NREF',
250 B_RGB_32_BIT_TYPE = 'RGBB',
251 B_RGB_COLOR_TYPE = 'RGBC',
252 B_SIZE_TYPE = 'SIZE',
253 B_SIZE_T_TYPE = 'SIZT',
254 B_SSIZE_T_TYPE = 'SSZT',
255 B_STRING_LIST_TYPE = 'STRL',
256 B_TIME_TYPE = 'TIME',
257 B_UINT16_TYPE = 'USHT',
258 B_UINT32_TYPE = 'ULNG',
259 B_UINT64_TYPE = 'ULLG',
260 B_UINT8_TYPE = 'UBYT',
261 B_VECTOR_ICON_TYPE = 'VICN',
262 B_XATTR_TYPE = 'XATR',
263 B_NETWORK_ADDRESS_TYPE = 'NWAD',
264 B_MIME_STRING_TYPE = 'MIMS',
265#endif
266 case B_STRING_TYPE:
267 text = message->FindString(nameFound, j);
268 break;
269 case B_INT32_TYPE:
270 {
271 int32 val = message->FindInt32(nameFound, j);
272 text.SetToFormat("%d (%#010x)", val, val);
273 break;
274 }
275 case B_POINT_TYPE:
276 {
277 BPoint val = message->FindPoint(nameFound, j);
278 text.SetToFormat("X: %f Y: %f", val.x, val.y);
279 break;
280 }
281 default:
282 text.SetTo("TODO: unhandled message content type");
283 break;
284 }
285
286 BRow* subRow = new BRow();
287 subRow->SetField(new BStringField(name), 0);
288 subRow->SetField(new BStringField(text), 1);
289 fEventList->AddRow(subRow, row);
290 }
291
292 }
293 }
294
295 break;
296 }
PulkoMandyee68b1e2023-04-21 22:54:09 +0200297 case B_ABOUT_REQUESTED:
298 {
299 be_app_messenger.SendMessage(B_ABOUT_REQUESTED);
300 break;
301 }
PulkoMandy69eec3e2023-04-10 15:22:28 +0200302 default:
303 BWindow::MessageReceived(message);
304 break;
305 }
306 }
307
308private:
309 BColumnListView* fEventList;
310};
311
312
313class LoggerApp: public BApplication
314{
315public:
316 LoggerApp()
317 : BApplication("application/x-vnd.ml-BeDCApp")
318 {
PulkoMandyee68b1e2023-04-21 22:54:09 +0200319 }
320
321 void ReadyToRun() override
322 {
323 BApplication::ReadyToRun();
324 fActiveLogWindow = new LoggerWindow();
325 fActiveLogWindow->Show();
326 }
327
328 void AboutRequested() override
329 {
330 BAboutWindow* about = new BAboutWindow("Dev Console", "application/x-vnd.ml-BeDCApp");
331 about->AddDescription("Display log messages from other applications");
332 about->AddCopyright(2023, "Adrien Destugues");
333 about->Show();
PulkoMandy69eec3e2023-04-10 15:22:28 +0200334 }
335
336 void MessageReceived(BMessage* message) override
337 {
338 switch(message->what) {
339 case BEDC_MESSAGE:
PulkoMandyee68b1e2023-04-21 22:54:09 +0200340 DetachCurrentMessage();
341 fActiveLogWindow->PostMessage(message);
PulkoMandy69eec3e2023-04-10 15:22:28 +0200342 break;
343 default:
344 BApplication::MessageReceived(message);
345 break;
346 }
347 }
PulkoMandyee68b1e2023-04-21 22:54:09 +0200348
349private:
350 BWindow* fActiveLogWindow;
PulkoMandy69eec3e2023-04-10 15:22:28 +0200351};
352
353
354int main(void)
355{
356 LoggerApp app;
357 app.Run();
358}