xref: /haiku/src/apps/activitymonitor/ActivityWindow.cpp (revision 4f2fd49bdc6078128b1391191e4edac647044c3d)
1 /*
2  * Copyright 2008, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 
7 #include "ActivityWindow.h"
8 
9 #include <stdio.h>
10 
11 #include <Application.h>
12 #include <File.h>
13 #include <FindDirectory.h>
14 #ifdef __HAIKU__
15 #include <GroupLayout.h>
16 #endif
17 #include <Menu.h>
18 #include <MenuBar.h>
19 #include <MenuItem.h>
20 #include <Path.h>
21 #include <Roster.h>
22 
23 #include "ActivityMonitor.h"
24 #include "ActivityView.h"
25 #include "DataSource.h"
26 
27 
28 static const uint32 kMsgAddView = 'advw';
29 
30 
31 ActivityWindow::ActivityWindow()
32 	: BWindow(BRect(100, 100, 500, 350), "ActivityMonitor", B_TITLED_WINDOW,
33 		B_ASYNCHRONOUS_CONTROLS | B_QUIT_ON_WINDOW_CLOSE)
34 {
35 	BMessage settings;
36 	_LoadSettings(settings);
37 
38 	BRect frame;
39 	if (settings.FindRect("window frame", &frame) == B_OK) {
40 		MoveTo(frame.LeftTop());
41 		ResizeTo(frame.Width(), frame.Height());
42 	}
43 
44 #ifdef __HAIKU__
45 	BGroupLayout* layout = new BGroupLayout(B_VERTICAL);
46 	SetLayout(layout);
47 
48 	// create GUI
49 
50 	BMenuBar* menuBar = new BMenuBar("menu");
51 	layout->AddView(menuBar);
52 
53 	fLayout = new BGroupLayout(B_VERTICAL);
54 	float inset = ceilf(be_plain_font->Size() * 0.7);
55 	fLayout->SetInsets(inset, inset, inset, inset);
56 	fLayout->SetSpacing(inset);
57 
58 	BView* top = new BView("top", 0, fLayout);
59 	top->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
60 	layout->AddView(top);
61 
62 	BMessage viewState;
63 	int32 count = 0;
64 	for (int32 i = 0; settings.FindMessage("activity view", i, &viewState)
65 			== B_OK; i++) {
66 		ActivityView* view = new ActivityView("ActivityMonitor", &viewState);
67 		fLayout->AddItem(view->CreateHistoryLayoutItem());
68 		fLayout->AddItem(view->CreateLegendLayoutItem());
69 		count++;
70 	}
71 	if (count == 0) {
72 		// Add default views (memory & CPU usage)
73 		_AddDefaultView();
74 		_AddDefaultView();
75 	}
76 #else	// !__HAIKU__
77 	BView *layout = new BView(Bounds(), "topmost", B_FOLLOW_NONE, 0);
78 	AddChild(layout);
79 
80 	// create GUI
81 	BRect mbRect(Bounds());
82 	mbRect.bottom = 10;
83 	BMenuBar* menuBar = new BMenuBar(mbRect, "menu");
84 	layout->AddChild(menuBar);
85 
86 	BRect topRect(Bounds());
87 	topRect.top = menuBar->Bounds().bottom + 1;
88 
89 	BView* top = new BView(topRect, "top", B_FOLLOW_ALL, 0);
90 	top->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
91 	layout->AddChild(top);
92 
93 	BMessage viewState;
94 	int32 count = 0;
95 	ActivityView *aview;
96 	BRect rect;
97 	for (int32 i = 0; settings.FindMessage("activity view", i, &viewState)
98 			== B_OK; i++) {
99 		aview = new ActivityView("ActivityMonitor", &viewState);
100 		if (!rect.IsValid())
101 			rect = aview->Bounds();
102 		else
103 			rect.OffsetBySelf(0.0, aview->Bounds().Height());
104 		top->AddChild(aview);
105 		count++;
106 	}
107 	if (count == 0)
108 		top->AddChild(new ActivityView("ActivityMonitor", NULL));
109 
110 #endif
111 	// add menu
112 
113 	// "File" menu
114 	BMenu* menu = new BMenu("File");
115 	BMenuItem* item;
116 
117 	menu->AddItem(new BMenuItem("Add View", new BMessage(kMsgAddView)));
118 	menu->AddSeparatorItem();
119 
120 	menu->AddItem(item = new BMenuItem("About ActivityMonitor" B_UTF8_ELLIPSIS,
121 		new BMessage(B_ABOUT_REQUESTED)));
122 	menu->AddSeparatorItem();
123 
124 	menu->AddItem(new BMenuItem("Quit", new BMessage(B_QUIT_REQUESTED), 'Q'));
125 	menu->SetTargetForItems(this);
126 	item->SetTarget(be_app);
127 	menuBar->AddItem(menu);
128 }
129 
130 
131 ActivityWindow::~ActivityWindow()
132 {
133 }
134 
135 
136 status_t
137 ActivityWindow::_OpenSettings(BFile& file, uint32 mode)
138 {
139 	BPath path;
140 	if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) != B_OK)
141 		return B_ERROR;
142 
143 	path.Append("ActivityMonitor settings");
144 
145 	return file.SetTo(path.Path(), mode);
146 }
147 
148 
149 status_t
150 ActivityWindow::_LoadSettings(BMessage& settings)
151 {
152 	BFile file;
153 	status_t status = _OpenSettings(file, B_READ_ONLY);
154 	if (status < B_OK)
155 		return status;
156 
157 	return settings.Unflatten(&file);
158 }
159 
160 
161 status_t
162 ActivityWindow::_SaveSettings()
163 {
164 	BFile file;
165 	status_t status = _OpenSettings(file, B_WRITE_ONLY | B_CREATE_FILE
166 		| B_ERASE_FILE);
167 	if (status < B_OK)
168 		return status;
169 
170 	BMessage settings('actm');
171 	status = settings.AddRect("window frame", Frame());
172 	if (status != B_OK)
173 		return status;
174 
175 #ifdef __HAIKU__
176 	BView* top = fLayout->View();
177 #else
178 	BView* top = ChildAt(0);
179 #endif
180 	int32 count = top->CountChildren();
181 	for (int32 i = 0; i < count; i++) {
182 		ActivityView* view = dynamic_cast<ActivityView*>(top->ChildAt(i));
183 		if (view == NULL)
184 			continue;
185 
186 		BMessage* viewState = new BMessage;
187 		status = view->SaveState(*viewState);
188 		if (status == B_OK)
189 			status = settings.AddMessage("activity view", viewState);
190 		if (status != B_OK) {
191 			delete viewState;
192 			break;
193 		}
194 	}
195 
196 	if (status == B_OK)
197 		status = settings.Flatten(&file);
198 
199 	return status;
200 }
201 
202 
203 int32
204 ActivityWindow::ActivityViewCount()
205 {
206 #ifdef __HAIKU__
207 	return fLayout->View()->CountChildren();
208 #else
209 	return 1;
210 #endif
211 }
212 
213 
214 void
215 ActivityWindow::_MessageDropped(BMessage* message)
216 {
217 	entry_ref ref;
218 	if (message->FindRef("refs", &ref) != B_OK) {
219 		// TODO: If app, then launch it, and add ActivityView for this one?
220 	}
221 }
222 
223 
224 void
225 ActivityWindow::_AddDefaultView()
226 {
227 	ActivityView* view = new ActivityView("ActivityMonitor", NULL);
228 
229 	switch (ActivityViewCount()) {
230 		case 0:
231 			// The first view defaults to memory usage
232 			view->AddDataSource(new UsedMemoryDataSource());
233 			view->AddDataSource(new CachedMemoryDataSource());
234 			break;
235 		case 2:
236 			// The third view defaults to network in/out
237 			view->AddDataSource(new NetworkUsageDataSource(true));
238 			view->AddDataSource(new NetworkUsageDataSource(false));
239 			break;
240 		case 1:
241 		default:
242 			// Everything beyond that defaults to a CPU usage view
243 			view->AddDataSource(new CPUUsageDataSource());
244 			break;
245 	}
246 
247 	fLayout->AddItem(view->CreateHistoryLayoutItem());
248 	fLayout->AddItem(view->CreateLegendLayoutItem());
249 }
250 
251 
252 void
253 ActivityWindow::MessageReceived(BMessage* message)
254 {
255 	if (message->WasDropped()) {
256 		_MessageDropped(message);
257 		return;
258 	}
259 
260 	switch (message->what) {
261 		case B_REFS_RECEIVED:
262 		case B_SIMPLE_DATA:
263 			_MessageDropped(message);
264 			break;
265 
266 		case kMsgAddView:
267 		{
268 #ifdef __HAIKU__
269 			BView* firstView = fLayout->View()->ChildAt(0);
270 
271 			_AddDefaultView();
272 
273 			if (firstView != NULL)
274 				ResizeBy(0, firstView->Bounds().Height() + fLayout->Spacing());
275 #endif
276 			break;
277 		}
278 
279 		case kMsgRemoveView:
280 		{
281 #ifdef __HAIKU__
282 			BView* view;
283 			if (message->FindPointer("view", (void**)&view) != B_OK)
284 				break;
285 
286 			view->RemoveSelf();
287 			ResizeBy(0, -view->Bounds().Height() - fLayout->Spacing());
288 			delete view;
289 #endif
290 			break;
291 		}
292 
293 		default:
294 			BWindow::MessageReceived(message);
295 			break;
296 	}
297 }
298 
299 
300 bool
301 ActivityWindow::QuitRequested()
302 {
303 	_SaveSettings();
304 	be_app->PostMessage(B_QUIT_REQUESTED);
305 	return true;
306 }
307