xref: /haiku/src/apps/debugger/user_interface/gui/expression_eval_window/ExpressionEvaluationWindow.cpp (revision f0650dc98fed895fc134a359aab99c27de6a0c6a)
1 /*
2  * Copyright 2014-2015, Rene Gollent, rene@gollent.com.
3  * Distributed under the terms of the MIT License.
4  */
5 #include "ExpressionEvaluationWindow.h"
6 
7 #include <Button.h>
8 #include <LayoutBuilder.h>
9 #include <MenuField.h>
10 #include <String.h>
11 #include <TextControl.h>
12 
13 #include "AutoLocker.h"
14 #include "CppLanguage.h"
15 #include "FunctionDebugInfo.h"
16 #include "FunctionInstance.h"
17 #include "MessageCodes.h"
18 #include "SourceLanguage.h"
19 #include "SpecificImageDebugInfo.h"
20 #include "StackFrame.h"
21 #include "StackTrace.h"
22 #include "Thread.h"
23 #include "UiUtils.h"
24 #include "UserInterface.h"
25 #include "ValueNodeManager.h"
26 
27 
28 enum {
29 	MSG_THREAD_SELECTION_CHANGED	= 'thsc',
30 	MSG_FRAME_SELECTION_CHANGED		= 'frsc'
31 };
32 
33 
34 ExpressionEvaluationWindow::ExpressionEvaluationWindow(BHandler* closeTarget,
35 		::Team* team, UserInterfaceListener* listener)
36 	:
37 	BWindow(BRect(), "Evaluate Expression", B_TITLED_WINDOW,
38 		B_AUTO_UPDATE_SIZE_LIMITS | B_CLOSE_ON_ESCAPE),
39 	fExpressionInput(NULL),
40 	fThreadList(NULL),
41 	fFrameList(NULL),
42 	fVariablesView(NULL),
43 	fCloseButton(NULL),
44 	fEvaluateButton(NULL),
45 	fCloseTarget(closeTarget),
46 	fCurrentLanguage(NULL),
47 	fFallbackLanguage(NULL),
48 	fTeam(team),
49 	fSelectedThread(NULL),
50 	fSelectedFrame(NULL),
51 	fListener(listener)
52 {
53 	team->AddListener(this);
54 }
55 
56 
57 ExpressionEvaluationWindow::~ExpressionEvaluationWindow()
58 {
59 	fTeam->RemoveListener(this);
60 
61 	if (fCurrentLanguage != NULL)
62 		fCurrentLanguage->ReleaseReference();
63 
64 	if (fFallbackLanguage != NULL)
65 		fFallbackLanguage->ReleaseReference();
66 
67 	if (fSelectedThread != NULL)
68 		fSelectedThread->ReleaseReference();
69 
70 	if (fSelectedFrame != NULL)
71 		fSelectedFrame->ReleaseReference();
72 }
73 
74 
75 ExpressionEvaluationWindow*
76 ExpressionEvaluationWindow::Create(BHandler* closeTarget, ::Team* team,
77 	UserInterfaceListener* listener)
78 {
79 	ExpressionEvaluationWindow* self = new ExpressionEvaluationWindow(
80 		closeTarget, team, listener);
81 
82 	try {
83 		self->_Init();
84 	} catch (...) {
85 		delete self;
86 		throw;
87 	}
88 
89 	return self;
90 
91 }
92 
93 
94 void
95 ExpressionEvaluationWindow::Show()
96 {
97 	CenterOnScreen();
98 	BWindow::Show();
99 }
100 
101 
102 bool
103 ExpressionEvaluationWindow::QuitRequested()
104 {
105 	BMessenger messenger(fCloseTarget);
106 	messenger.SendMessage(MSG_EXPRESSION_WINDOW_CLOSED);
107 
108 	return BWindow::QuitRequested();
109 }
110 
111 
112 void
113 ExpressionEvaluationWindow::MessageReceived(BMessage* message)
114 {
115 	switch (message->what) {
116 		case MSG_THREAD_SELECTION_CHANGED:
117 		{
118 			int32 threadID;
119 			if (message->FindInt32("thread", &threadID) != B_OK)
120 				threadID = -1;
121 
122 			_HandleThreadSelectionChanged(threadID);
123 			break;
124 		}
125 
126 		case MSG_FRAME_SELECTION_CHANGED:
127 		{
128 			if (fSelectedThread == NULL)
129 				break;
130 
131 			int32 frameIndex;
132 			if (message->FindInt32("frame", &frameIndex) != B_OK)
133 				frameIndex = -1;
134 
135 			_HandleFrameSelectionChanged(frameIndex);
136 			break;
137 		}
138 
139 		case MSG_EVALUATE_EXPRESSION:
140 		{
141 			BMessage message(MSG_ADD_NEW_EXPRESSION);
142 			message.AddString("expression", fExpressionInput->Text());
143 			BMessenger(fVariablesView).SendMessage(&message);
144 			break;
145 		}
146 
147 		default:
148 			BWindow::MessageReceived(message);
149 			break;
150 	}
151 
152 }
153 
154 
155 void
156 ExpressionEvaluationWindow::ValueNodeValueRequested(CpuState* cpuState,
157 	ValueNodeContainer* container, ValueNode* valueNode)
158 {
159 	fListener->ValueNodeValueRequested(cpuState, container, valueNode);
160 }
161 
162 
163 void
164 ExpressionEvaluationWindow::ExpressionEvaluationRequested(ExpressionInfo* info,
165 	StackFrame* frame, ::Thread* thread)
166 {
167 	SourceLanguage* language = fCurrentLanguage;
168 	if (fCurrentLanguage == NULL)
169 		language = fFallbackLanguage;
170 	fListener->ExpressionEvaluationRequested(language, info, frame, thread);
171 }
172 
173 
174 void
175 ExpressionEvaluationWindow::ValueNodeWriteRequested(ValueNode* node,
176 	CpuState* state, Value* newValue)
177 {
178 }
179 
180 
181 void
182 ExpressionEvaluationWindow::_Init()
183 {
184 	ValueNodeManager* nodeManager = new ValueNodeManager(false);
185 	fExpressionInput = new BTextControl("Expression:", NULL, NULL);
186 	BLayoutItem* labelItem = fExpressionInput->CreateLabelLayoutItem();
187 	BLayoutItem* inputItem = fExpressionInput->CreateTextViewLayoutItem();
188 	inputItem->SetExplicitMinSize(BSize(200.0, B_SIZE_UNSET));
189 	inputItem->SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, B_SIZE_UNSET));
190 	labelItem->View()->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
191 
192 	BLayoutBuilder::Group<>(this, B_VERTICAL)
193 		.SetInsets(B_USE_DEFAULT_SPACING)
194 		.AddGroup(B_HORIZONTAL, 4.0f)
195 			.Add((fThreadList = new BMenuField("threadList", "Thread:",
196 					new BMenu("Thread"))))
197 			.Add((fFrameList = new BMenuField("frameList", "Frame:",
198 					new BMenu("Frame"))))
199 		.End()
200 		.AddGroup(B_HORIZONTAL, 4.0f)
201 			.Add(labelItem)
202 			.Add(inputItem)
203 		.End()
204 		.Add(fVariablesView = VariablesView::Create(this, nodeManager))
205 		.AddGroup(B_HORIZONTAL, 4.0f)
206 			.AddGlue()
207 			.Add((fCloseButton = new BButton("Close",
208 					new BMessage(B_QUIT_REQUESTED))))
209 			.Add((fEvaluateButton = new BButton("Evaluate",
210 					new BMessage(MSG_EVALUATE_EXPRESSION))))
211 		.End();
212 
213 	fCloseButton->SetTarget(this);
214 	fEvaluateButton->SetTarget(this);
215 	fExpressionInput->TextView()->MakeFocus(true);
216 
217 	fThreadList->Menu()->SetLabelFromMarked(true);
218 	fFrameList->Menu()->SetLabelFromMarked(true);
219 
220 	fThreadList->Menu()->AddItem(new BMenuItem("<None>",
221 			new BMessage(MSG_THREAD_SELECTION_CHANGED)));
222 	fFrameList->Menu()->AddItem(new BMenuItem("<None>",
223 			new BMessage(MSG_FRAME_SELECTION_CHANGED)));
224 
225 	_UpdateThreadList();
226 
227 	fFallbackLanguage = new CppLanguage();
228 }
229 
230 
231 void
232 ExpressionEvaluationWindow::_HandleThreadSelectionChanged(int32 threadID)
233 {
234 	if (fSelectedThread != NULL) {
235 		fSelectedThread->ReleaseReference();
236 		fSelectedThread = NULL;
237 	}
238 
239 	AutoLocker< ::Team> teamLocker(fTeam);
240 	fSelectedThread = fTeam->ThreadByID(threadID);
241 	if (fSelectedThread != NULL)
242 		fSelectedThread->AcquireReference();
243 
244 	_UpdateFrameList();
245 
246 	fVariablesView->SetStackFrame(fSelectedThread, fSelectedFrame);
247 }
248 
249 
250 void
251 ExpressionEvaluationWindow::_HandleFrameSelectionChanged(int32 index)
252 {
253 	if (fSelectedFrame != NULL) {
254 		fSelectedFrame->ReleaseReference();
255 		fSelectedFrame = NULL;
256 	}
257 
258 	if (fCurrentLanguage != NULL) {
259 		fCurrentLanguage->ReleaseReference();
260 		fCurrentLanguage = NULL;
261 	}
262 
263 	AutoLocker< ::Team> teamLocker(fTeam);
264 	StackTrace* stackTrace = fSelectedThread->GetStackTrace();
265 	if (stackTrace != NULL) {
266 		fSelectedFrame = stackTrace->FrameAt(index);
267 		if (fSelectedFrame != NULL) {
268 			fSelectedFrame->AcquireReference();
269 
270 			FunctionInstance* instance = fSelectedFrame->Function();
271 			if (instance != NULL) {
272 				FunctionDebugInfo* functionInfo
273 					= instance->GetFunctionDebugInfo();
274 				SpecificImageDebugInfo* imageInfo =
275 					functionInfo->GetSpecificImageDebugInfo();
276 
277 				if (imageInfo->GetSourceLanguage(functionInfo,
278 						fCurrentLanguage) == B_OK) {
279 					fCurrentLanguage->AcquireReference();
280 				}
281 			}
282 		}
283 	}
284 
285 	fVariablesView->SetStackFrame(fSelectedThread, fSelectedFrame);
286 }
287 
288 
289 void
290 ExpressionEvaluationWindow::_UpdateThreadList()
291 {
292 	AutoLocker< ::Team> teamLocker(fTeam);
293 
294 	BMenu* frameMenu = fFrameList->Menu();
295 	while (frameMenu->CountItems() > 1)
296 		delete frameMenu->RemoveItem(1);
297 
298 	BMenu* threadMenu = fThreadList->Menu();
299 	while (threadMenu->CountItems() > 1)
300 		delete threadMenu->RemoveItem(1);
301 
302 	const ThreadList& threads = fTeam->Threads();
303 	for (ThreadList::ConstIterator it = threads.GetIterator();
304 		::Thread* thread = it.Next();) {
305 		if (thread->State() != THREAD_STATE_STOPPED)
306 			continue;
307 
308 		BString nameString;
309 		nameString.SetToFormat("%" B_PRId32 ": %s", thread->ID(),
310 			thread->Name());
311 
312 		BMessage* message = new(std::nothrow) BMessage(
313 			MSG_THREAD_SELECTION_CHANGED);
314 		if (message == NULL)
315 			return;
316 
317 		message->AddInt32("thread", thread->ID());
318 
319 		BMenuItem* item = new(std::nothrow) BMenuItem(nameString,
320 			message);
321 		if (item == NULL)
322 			return;
323 
324 		if (!threadMenu->AddItem(item))
325 			return;
326 
327 		if (fSelectedThread == NULL) {
328 			item->SetMarked(true);
329 			_HandleThreadSelectionChanged(thread->ID());
330 		}
331 	}
332 
333 	if (fSelectedThread == NULL)
334 		frameMenu->ItemAt(0L)->SetMarked(true);
335 
336 }
337 
338 
339 void
340 ExpressionEvaluationWindow::_UpdateFrameList()
341 {
342 	AutoLocker< ::Team> teamLocker(fTeam);
343 
344 	BMenu* frameMenu = fFrameList->Menu();
345 	while (frameMenu->CountItems() > 1)
346 		delete frameMenu->RemoveItem(1);
347 
348 	frameMenu->ItemAt(0L)->SetMarked(true);
349 
350 	if (fSelectedThread == NULL)
351 		return;
352 
353 	StackTrace* stackTrace = fSelectedThread->GetStackTrace();
354 	if (stackTrace == NULL)
355 		return;
356 
357  	char buffer[128];
358 	for (int32 i = 0; i < stackTrace->CountFrames(); i++) {
359 		StackFrame* frame = stackTrace->FrameAt(i);
360 		UiUtils::FunctionNameForFrame(frame, buffer, sizeof(buffer));
361 
362 		BMessage* message = new(std::nothrow) BMessage(
363 			MSG_FRAME_SELECTION_CHANGED);
364 		if (message == NULL)
365 			return;
366 
367 		message->AddInt32("frame", i);
368 
369 		BMenuItem* item = new(std::nothrow) BMenuItem(buffer,
370 			message);
371 		if (item == NULL)
372 			return;
373 
374 		if (!frameMenu->AddItem(item))
375 			return;
376 
377 		if (fSelectedFrame == NULL) {
378 			item->SetMarked(true);
379 			_HandleFrameSelectionChanged(i);
380 		}
381 	}
382 }
383