1/*
2 * Copyright 2012, Rene Gollent, rene@gollent.com.
3 * Distributed under the terms of the MIT License.
4 */
5#include "WatchPromptWindow.h"
6
7#include <Alert.h>
8#include <Button.h>
9#include <LayoutBuilder.h>
10#include <Menu.h>
11#include <MenuField.h>
12#include <MenuItem.h>
13#include <String.h>
14#include <TextControl.h>
15
16#include <ExpressionParser.h>
17
18#include "Architecture.h"
19#include "MessageCodes.h"
20#include "UserInterface.h"
21#include "Watchpoint.h"
22
23
24WatchPromptWindow::WatchPromptWindow(Architecture* architecture,
25	target_addr_t address, uint32 type, int32 length,
26	UserInterfaceListener* listener)
27	:
28	BWindow(BRect(), "Edit Watchpoint", B_FLOATING_WINDOW,
29		B_AUTO_UPDATE_SIZE_LIMITS | B_CLOSE_ON_ESCAPE),
30	fInitialAddress(address),
31	fInitialType(type),
32	fInitialLength(length),
33	fArchitecture(architecture),
34	fAddressInput(NULL),
35	fLengthInput(NULL),
36	fTypeField(NULL),
37	fListener(listener)
38{
39	fArchitecture->AcquireReference();
40}
41
42
43WatchPromptWindow::~WatchPromptWindow()
44{
45	fArchitecture->ReleaseReference();
46}
47
48
49WatchPromptWindow*
50WatchPromptWindow::Create(Architecture* architecture, target_addr_t address,
51	uint32 type, int32 length, UserInterfaceListener* listener)
52{
53	WatchPromptWindow* self = new WatchPromptWindow(architecture, address,
54		type, length, listener);
55
56	try {
57		self->_Init();
58	} catch (...) {
59		delete self;
60		throw;
61	}
62
63	return self;
64
65}
66
67void
68WatchPromptWindow::_Init()
69{
70	BString text;
71	text.SetToFormat("0x%" B_PRIx64, fInitialAddress);
72	fAddressInput = new BTextControl("Address:", text, NULL);
73
74	text.SetToFormat("%" B_PRId32, fInitialLength);
75	fLengthInput = new BTextControl("Length:", text, NULL);
76
77	int32 maxDebugRegisters = 0;
78	int32 maxBytesPerRegister = 0;
79	uint8 debugCapabilityFlags = 0;
80	fArchitecture->GetWatchpointDebugCapabilities(maxDebugRegisters,
81		maxBytesPerRegister, debugCapabilityFlags);
82
83	BMenu* typeMenu = new BMenu("Watch Type");
84
85	BMenuItem* watchTypeItem = new BMenuItem("Read", NULL);
86	watchTypeItem->SetEnabled(
87		(debugCapabilityFlags & WATCHPOINT_CAPABILITY_FLAG_READ) != 0);
88	typeMenu->AddItem(watchTypeItem);
89
90	watchTypeItem = new BMenuItem("Write", NULL);
91	watchTypeItem->SetEnabled(
92		(debugCapabilityFlags & WATCHPOINT_CAPABILITY_FLAG_WRITE) != 0);
93	typeMenu->AddItem(watchTypeItem);
94
95	watchTypeItem = new BMenuItem("Read/Write", NULL);
96	watchTypeItem->SetEnabled(
97		(debugCapabilityFlags & WATCHPOINT_CAPABILITY_FLAG_READ_WRITE) != 0);
98	typeMenu->AddItem(watchTypeItem);
99
100	fTypeField = new BMenuField("Type:", typeMenu);
101	BLayoutItem* labelItem = fTypeField->CreateLabelLayoutItem();
102	labelItem->View()->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
103	BLayoutBuilder::Group<>(this, B_VERTICAL)
104		.SetInsets(4.0f, 4.0f, 4.0f, 4.0f)
105		.AddGroup(B_HORIZONTAL, 4.0f)
106			.Add(fAddressInput)
107		.End()
108		.AddGroup(B_HORIZONTAL, 4.0f)
109			.Add(fLengthInput)
110			.Add(labelItem)
111			.Add(fTypeField->CreateMenuBarLayoutItem())
112		.End()
113		.AddGroup(B_HORIZONTAL, 4.0f)
114			.AddGlue()
115			.Add((fWatchButton = new BButton("Set",
116					new BMessage(MSG_SET_WATCHPOINT))))
117			.Add((fCancelButton = new BButton("Cancel",
118					new BMessage(B_QUIT_REQUESTED))))
119		.End();
120
121	fWatchButton->SetTarget(this);
122	fCancelButton->SetTarget(this);
123
124	fTypeField->Menu()->SetLabelFromMarked(true);
125	fTypeField->Menu()->ItemAt(fInitialType)->SetMarked(true);
126}
127
128void
129WatchPromptWindow::Show()
130{
131	CenterOnScreen();
132	BWindow::Show();
133}
134
135void
136WatchPromptWindow::MessageReceived(BMessage* message)
137{
138	switch (message->what) {
139		case MSG_SET_WATCHPOINT:
140		{
141			target_addr_t address = 0;
142			int32 length = 0;
143			ExpressionParser parser;
144			parser.SetSupportHexInput(true);
145			BString errorMessage;
146			try {
147				address = parser.EvaluateToInt64(fAddressInput->Text());
148				length = (int32)parser.EvaluateToInt64(fLengthInput->Text());
149			} catch(ParseException parseError) {
150				errorMessage.SetToFormat("Failed to parse data: %s",
151					parseError.message.String());
152			} catch(...) {
153				errorMessage.SetToFormat(
154					"Unknown error while parsing address");
155			}
156
157			if (!errorMessage.IsEmpty()) {
158				BAlert* alert = new(std::nothrow) BAlert("Edit Watchpoint",
159					errorMessage.String(), "Close");
160				if (alert != NULL)
161					alert->Go();
162				break;
163			}
164
165			fListener->ClearWatchpointRequested(fInitialAddress);
166			fListener->SetWatchpointRequested(address, fTypeField->Menu()
167					->IndexOf(fTypeField->Menu()->FindMarked()), length, true);
168
169			PostMessage(B_QUIT_REQUESTED);
170
171			break;
172		}
173		default:
174			BWindow::MessageReceived(message);
175			break;
176	}
177
178}
179