xref: /haiku/src/apps/diskusage/ControlsView.cpp (revision c90684742e7361651849be4116d0e5de3a817194)
1 /*
2  * Copyright (c) 2008 Stephan Aßmus <superstippi@gmx.de>. All rights reserved.
3  * Distributed under the terms of the MIT/X11 license.
4  *
5  * Copyright (c) 1999 Mike Steed. You are free to use and distribute this software
6  * as long as it is accompanied by it's documentation and this copyright notice.
7  * The software comes with no warranty, etc.
8  */
9 
10 
11 #include "ControlsView.h"
12 
13 #include <Bitmap.h>
14 #include <Box.h>
15 #include <TabView.h>
16 #include <NodeMonitor.h>
17 #include <Path.h>
18 #include <PopUpMenu.h>
19 #include <SupportDefs.h>
20 #include <Volume.h>
21 #include <VolumeRoster.h>
22 #include <Window.h>
23 
24 #include <LayoutBuilder.h>
25 
26 #include "Common.h"
27 #include "VolumeView.h"
28 
29 
30 class VolumeTab: public BTab {
31 public:
32 								VolumeTab(BVolume* volume);
33 	virtual						~VolumeTab();
34 
35 			BVolume*			Volume() const
36 									{ return fVolume; }
37 			float				IconWidth() const;
38 
39 	virtual	void				DrawLabel(BView* owner, BRect frame);
40 
41 private:
42 			BBitmap*			fIcon;
43 			BVolume*			fVolume;
44 };
45 
46 
47 VolumeTab::VolumeTab(BVolume* volume)
48 	:
49 	BTab(),
50 	fIcon(new BBitmap(BRect(0, 0, 15, 15), B_RGBA32)),
51 	fVolume(volume)
52 {
53 	if (fVolume->GetIcon(fIcon, B_MINI_ICON) < B_OK) {
54 		delete fIcon;
55 		fIcon = NULL;
56 	}
57 }
58 
59 
60 float
61 VolumeTab::IconWidth() const
62 {
63 	if (fIcon != NULL)
64 		// add a small margin
65 		return fIcon->Bounds().Width() + kSmallHMargin;
66 	else
67 		return 0.0f;
68 }
69 
70 
71 void
72 VolumeTab::DrawLabel(BView* owner, BRect frame)
73 {
74 	owner->SetDrawingMode(B_OP_OVER);
75 	if (fIcon != NULL) {
76 		owner->MovePenTo(frame.left + kSmallHMargin,
77 			(frame.top + frame.bottom - fIcon->Bounds().Height()) / 2.0);
78 		owner->DrawBitmap(fIcon);
79 	}
80 
81 	font_height fh;
82 	owner->GetFontHeight(&fh);
83 
84 	owner->SetHighColor(ui_color(B_CONTROL_TEXT_COLOR));
85 	owner->DrawString(Label(),
86 		BPoint(frame.left + IconWidth() + kSmallHMargin,
87 			(frame.top + frame.bottom - fh.ascent - fh.descent) / 2.0
88 				+ fh.ascent));
89 }
90 
91 
92 VolumeTab::~VolumeTab()
93 {
94 	delete fIcon;
95 	delete fVolume;
96 }
97 
98 
99 // #pragma mark -
100 
101 
102 class ControlsView::VolumeTabView: public BTabView {
103 public:
104 								VolumeTabView();
105 	virtual						~VolumeTabView();
106 
107 	virtual	void				AttachedToWindow();
108 	virtual	void				MessageReceived(BMessage* message);
109 	virtual BRect				TabFrame(int32 index) const;
110 
111 			BVolume*			FindDeviceFor(dev_t device,
112 									bool invoke = false);
113 
114 private:
115 			void				_AddVolume(dev_t device);
116 			void				_RemoveVolume(dev_t device);
117 
118 			BVolumeRoster*		fVolumeRoster;
119 };
120 
121 
122 ControlsView::VolumeTabView::VolumeTabView()
123 	:
124 	BTabView("volume_tabs", B_WIDTH_FROM_LABEL)
125 {
126 }
127 
128 
129 ControlsView::VolumeTabView::~VolumeTabView()
130 {
131 	fVolumeRoster->StopWatching();
132 	delete fVolumeRoster;
133 }
134 
135 
136 BRect
137 ControlsView::VolumeTabView::TabFrame(int32 index) const
138 {
139 	float height = BTabView::TabFrame(index).Height();
140 	float x = 0.0f;
141 	for (int32 i = 0; i < index; i++) {
142 		x += StringWidth(TabAt(i)->Label()) + 3.0f * kSmallHMargin
143 			+ ((VolumeTab*)TabAt(i))->IconWidth();
144 	}
145 
146 	return BRect(x, 0.0f,
147 		x + StringWidth(TabAt(index)->Label()) + 3.0f * kSmallHMargin
148 			+ ((VolumeTab*)TabAt(index))->IconWidth(),
149 		height);
150 }
151 
152 
153 void
154 ControlsView::VolumeTabView::AttachedToWindow()
155 {
156 	// Populate the menu with the persistent volumes.
157 	fVolumeRoster = new BVolumeRoster();
158 
159 	BVolume tempVolume;
160 	while (fVolumeRoster->GetNextVolume(&tempVolume) == B_OK) {
161 		if (tempVolume.IsPersistent()) {
162 			BVolume* volume = new BVolume(tempVolume);
163 			VolumeTab *item = new VolumeTab(volume);
164 			char name[B_PATH_NAME_LENGTH];
165 			volume->GetName(name);
166 			AddTab(new VolumeView(name, volume), item);
167 		}
168 	}
169 
170 	// Begin watching mount and unmount events.
171 	fVolumeRoster->StartWatching(BMessenger(this));
172 }
173 
174 
175 void
176 ControlsView::VolumeTabView::MessageReceived(BMessage* message)
177 {
178 	switch (message->what) {
179 		case B_NODE_MONITOR:
180 			switch (message->FindInt32("opcode")) {
181 				case B_DEVICE_MOUNTED:
182 					_AddVolume(message->FindInt32("new device"));
183 					break;
184 
185 				case B_DEVICE_UNMOUNTED:
186 					_RemoveVolume(message->FindInt32("device"));
187 					break;
188 			}
189 			break;
190 
191 		case kBtnRescan:
192 			ViewForTab(Selection())->MessageReceived(message);
193 			break;
194 
195 		case B_SIMPLE_DATA:
196 		case B_REFS_RECEIVED:
197 		{
198 			entry_ref ref;
199 
200 			for (int i = 0; message->FindRef("refs", i, &ref) == B_OK; i++) {
201 				BEntry entry(&ref, true);
202 				BPath path;
203 				entry.GetPath(&path);
204 				dev_t device = dev_for_path(path.Path());
205 
206 				for (int j = 0; VolumeTab* item = (VolumeTab*)TabAt(j); j++) {
207 					if (item->Volume()->Device() == device) {
208 						Select(j);
209 						((VolumeView*)(item->View()))->SetPath(path);
210 						break;
211 					}
212 				}
213 			}
214 			break;
215 		}
216 
217 		default:
218 			BTabView::MessageReceived(message);
219 			break;
220 	}
221 }
222 
223 
224 BVolume*
225 ControlsView::VolumeTabView::FindDeviceFor(dev_t device, bool invoke)
226 {
227 	BVolume* volume = NULL;
228 
229 	// Iterate through items looking for a BVolume representing this device.
230 	for (int i = 0; VolumeTab* item = (VolumeTab*)TabAt(i); i++) {
231 		if (item->Volume()->Device() == device) {
232 			volume = item->Volume();
233 			if (invoke)
234 				Select(i);
235 			break;
236 		}
237 	}
238 
239 	return volume;
240 }
241 
242 
243 void
244 ControlsView::VolumeTabView::_AddVolume(dev_t device)
245 {
246 	// Make sure the volume is not already in the menu.
247 	for (int i = 0; VolumeTab* item = (VolumeTab*)TabAt(i); i++) {
248 		if (item->Volume()->Device() == device)
249 			return;
250 	}
251 
252 	BVolume* volume = new BVolume(device);
253 
254 	VolumeTab* item = new VolumeTab(volume);
255 	char name[B_PATH_NAME_LENGTH];
256 	volume->GetName(name);
257 
258 	AddTab(new VolumeView(name, volume), item);
259 	Invalidate();
260 }
261 
262 
263 void
264 ControlsView::VolumeTabView::_RemoveVolume(dev_t device)
265 {
266 	for (int i = 0; VolumeTab* item = (VolumeTab*)TabAt(i); i++) {
267 		if (item->Volume()->Device() == device) {
268 			if (i == 0)
269 				Select(1);
270 			else
271 				Select(i - 1);
272 			RemoveTab(i);
273 			delete item;
274 			return;
275 		}
276 	}
277 }
278 
279 
280 // #pragma mark -
281 
282 
283 ControlsView::ControlsView()
284 	:
285 	BView(NULL, B_WILL_DRAW)
286 {
287 	SetLayout(new BGroupLayout(B_VERTICAL));
288 	fVolumeTabView = new VolumeTabView();
289 	AddChild(BLayoutBuilder::Group<>(B_VERTICAL)
290 		.Add(fVolumeTabView)
291 	);
292 }
293 
294 
295 void
296 ControlsView::MessageReceived(BMessage* msg)
297 {
298 	switch (msg->what) {
299 		case B_SIMPLE_DATA:
300 		case B_REFS_RECEIVED:
301 			fVolumeTabView->MessageReceived(msg);
302 			break;
303 
304 		case kBtnRescan:
305 			fVolumeTabView->MessageReceived(msg);
306 			break;
307 
308 		default:
309 			BView::MessageReceived(msg);
310 	}
311 }
312 
313 
314 ControlsView::~ControlsView()
315 {
316 }
317 
318 
319 void
320 ControlsView::ShowInfo(const FileInfo* info)
321 {
322 	((VolumeView*)fVolumeTabView->ViewForTab(
323 		fVolumeTabView->Selection()))->ShowInfo(info);
324 }
325 
326 
327 void
328 ControlsView::SetRescanEnabled(bool enabled)
329 {
330 	((VolumeView*)fVolumeTabView->ViewForTab(
331 		fVolumeTabView->Selection()))->SetRescanEnabled(enabled);
332 }
333 
334 
335 BVolume*
336 ControlsView::FindDeviceFor(dev_t device, bool invoke)
337 {
338 	return fVolumeTabView->FindDeviceFor(device, invoke);
339 }
340