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