2 * Copyright (c) 2008 Stephan Aßmus <superstippi@gmx.de>. All rights reserved.
3 * Distributed under the terms of the MIT/X11 license.
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.
11 #include "ControlsView.h"
18 #include <NodeMonitor.h>
20 #include <PopUpMenu.h>
22 #include <SupportDefs.h>
25 #include <VolumeRoster.h>
28 #include <LayoutBuilder.h>
30 #include "DiskUsage.h"
31 #include "VolumeView.h"
34 class VolumeTab
: public BTab
{
36 VolumeTab(BVolume
* volume
);
39 BVolume
* Volume() const
41 float IconWidth() const;
43 virtual void DrawLabel(BView
* owner
, BRect frame
);
44 virtual void DrawFocusMark(BView
* owner
, BRect frame
);
52 VolumeTab::VolumeTab(BVolume
* volume
)
55 fIcon(new BBitmap(BRect(0, 0, 15, 15), B_RGBA32
)),
58 if (fVolume
->GetIcon(fIcon
, B_MINI_ICON
) < B_OK
) {
66 VolumeTab::IconWidth() const
70 return fIcon
->Bounds().Width() + kSmallHMargin
;
77 VolumeTab::DrawLabel(BView
* owner
, BRect frame
)
79 owner
->SetDrawingMode(B_OP_OVER
);
81 owner
->MovePenTo(frame
.left
+ kSmallHMargin
,
82 (frame
.top
+ frame
.bottom
- fIcon
->Bounds().Height()) / 2.0);
83 owner
->DrawBitmap(fIcon
);
86 owner
->GetFontHeight(&fh
);
88 BString label
= Label();
90 owner
->TruncateString(&label
, B_TRUNCATE_END
,
91 frame
.Width() - IconWidth() - kSmallHMargin
);
93 owner
->SetHighColor(ui_color(B_CONTROL_TEXT_COLOR
));
94 owner
->DrawString(label
,
95 BPoint(frame
.left
+ IconWidth() + kSmallHMargin
,
96 (frame
.top
+ frame
.bottom
- fh
.ascent
- fh
.descent
) / 2.0
102 VolumeTab::DrawFocusMark(BView
* owner
, BRect frame
)
104 frame
.left
+= IconWidth();
105 BTab::DrawFocusMark(owner
, frame
);
109 VolumeTab::~VolumeTab()
119 class ControlsView::VolumeTabView
: public BTabView
{
122 virtual ~VolumeTabView();
124 virtual void AttachedToWindow();
125 virtual void MessageReceived(BMessage
* message
);
126 virtual BRect
TabFrame(int32 index
) const;
128 BVolume
* FindDeviceFor(dev_t device
,
129 bool invoke
= false);
132 void _AddVolume(dev_t device
);
133 void _RemoveVolume(dev_t device
);
135 BVolumeRoster
* fVolumeRoster
;
139 ControlsView::VolumeTabView::VolumeTabView()
141 BTabView("volume_tabs", B_WIDTH_FROM_LABEL
)
143 SetBorder(B_NO_BORDER
);
147 ControlsView::VolumeTabView::~VolumeTabView()
149 fVolumeRoster
->StopWatching();
150 delete fVolumeRoster
;
155 ControlsView::VolumeTabView::TabFrame(int32 index
) const
157 float height
= BTabView::TabFrame(index
).Height();
160 float minStringWidth
= StringWidth("Haiku");
161 int32 countTabs
= CountTabs();
163 // calculate the total width if no truncation is made at all
164 float averageWidth
= Frame().Width() / countTabs
;
166 // margins are the deltas with the average widths
167 float* margins
= new float[countTabs
];
168 for (int32 i
= 0; i
< countTabs
; i
++) {
169 float tabLabelWidth
= StringWidth(TabAt(i
)->Label());
170 if (tabLabelWidth
< minStringWidth
)
171 tabLabelWidth
= minStringWidth
;
173 float tabWidth
= tabLabelWidth
+ 3.0f
* kSmallHMargin
174 + ((VolumeTab
*)TabAt(i
))->IconWidth();
175 margins
[i
] = tabWidth
- averageWidth
;
179 // determine how much we should shave to show all tabs (truncating)
180 float toShave
= width
- Frame().Width();
182 if (toShave
> 0.0f
) {
183 // the thinest a tab can be to hold the minimum string
184 float minimumMargin
= minStringWidth
+ 3.0f
* kSmallHMargin
187 float averageToShave
;
190 we might have to do multiple passes because of the minimum
191 tab width we are imposing.
192 we could also fail to totally fit all tabs.
197 averageToShave
= toShave
/ countTabs
;
198 oldToShave
= toShave
;
199 for (int32 i
= 0; i
< countTabs
; i
++) {
200 float iconWidth
= ((VolumeTab
*)TabAt(i
))->IconWidth();
201 float newMargin
= max_c(margins
[i
] - averageToShave
,
202 minimumMargin
+ iconWidth
);
203 toShave
-= margins
[i
] - newMargin
;
204 margins
[i
] = newMargin
;
206 } while (toShave
> 0 && oldToShave
!= toShave
);
209 for (int i
= 0; i
< index
; i
++)
210 x
+= averageWidth
+ margins
[i
];
212 float margin
= margins
[index
];
215 return BRect(x
, 0.0f
, x
+ averageWidth
+ margin
, height
);
220 ControlsView::VolumeTabView::AttachedToWindow()
222 // Populate the menu with the persistent volumes.
223 fVolumeRoster
= new BVolumeRoster();
226 while (fVolumeRoster
->GetNextVolume(&tempVolume
) == B_OK
) {
227 if (!tempVolume
.IsPersistent())
230 char name
[B_PATH_NAME_LENGTH
];
231 if (tempVolume
.GetName(name
) != B_OK
)
234 if (strcmp(name
, "system") == 0
235 || strcmp(name
, "config") == 0) {
236 // Don't include virtual volumes.
240 BVolume
* volume
= new BVolume(tempVolume
);
241 VolumeView
* volumeView
= new VolumeView(name
, volume
);
242 VolumeTab
* volumeTab
= new VolumeTab(volume
);
243 AddTab(volumeView
, volumeTab
);
246 // Begin watching mount and unmount events.
247 fVolumeRoster
->StartWatching(BMessenger(this));
252 ControlsView::VolumeTabView::MessageReceived(BMessage
* message
)
254 switch (message
->what
) {
256 switch (message
->FindInt32("opcode")) {
257 case B_DEVICE_MOUNTED
:
258 _AddVolume(message
->FindInt32("new device"));
261 case B_DEVICE_UNMOUNTED
:
262 _RemoveVolume(message
->FindInt32("device"));
269 ViewForTab(Selection())->MessageReceived(message
);
273 case B_REFS_RECEIVED
:
277 for (int i
= 0; message
->FindRef("refs", i
, &ref
) == B_OK
; i
++) {
278 BEntry
entry(&ref
, true);
280 entry
.GetPath(&path
);
281 dev_t device
= dev_for_path(path
.Path());
283 for (int j
= 0; VolumeTab
* item
= (VolumeTab
*)TabAt(j
); j
++) {
284 if (item
->Volume()->Device() == device
) {
286 ((VolumeView
*)(item
->View()))->SetPath(path
);
295 BTabView::MessageReceived(message
);
302 ControlsView::VolumeTabView::FindDeviceFor(dev_t device
, bool invoke
)
304 BVolume
* volume
= NULL
;
306 // Iterate through items looking for a BVolume representing this device.
307 for (int i
= 0; VolumeTab
* item
= (VolumeTab
*)TabAt(i
); i
++) {
308 if (item
->Volume()->Device() == device
) {
309 volume
= item
->Volume();
321 ControlsView::VolumeTabView::_AddVolume(dev_t device
)
323 // Make sure the volume is not already in the menu.
324 for (int i
= 0; VolumeTab
* item
= (VolumeTab
*)TabAt(i
); i
++) {
325 if (item
->Volume()->Device() == device
)
329 BVolume
* volume
= new BVolume(device
);
331 VolumeTab
* item
= new VolumeTab(volume
);
332 char name
[B_PATH_NAME_LENGTH
];
333 volume
->GetName(name
);
335 AddTab(new VolumeView(name
, volume
), item
);
341 ControlsView::VolumeTabView::_RemoveVolume(dev_t device
)
343 for (int i
= 0; VolumeTab
* item
= (VolumeTab
*)TabAt(i
); i
++) {
344 if (item
->Volume()->Device() == device
) {
360 ControlsView::ControlsView()
362 BView(NULL
, B_WILL_DRAW
)
364 SetLayout(new BGroupLayout(B_VERTICAL
));
365 fVolumeTabView
= new VolumeTabView();
366 AddChild(BLayoutBuilder::Group
<>(B_VERTICAL
)
373 ControlsView::MessageReceived(BMessage
* msg
)
377 case B_REFS_RECEIVED
:
378 fVolumeTabView
->MessageReceived(msg
);
383 fVolumeTabView
->MessageReceived(msg
);
387 BView::MessageReceived(msg
);
392 ControlsView::~ControlsView()
398 ControlsView::ShowInfo(const FileInfo
* info
)
400 ((VolumeView
*)fVolumeTabView
->ViewForTab(
401 fVolumeTabView
->Selection()))->ShowInfo(info
);
406 ControlsView::EnableRescan()
408 ((VolumeView
*)fVolumeTabView
->ViewForTab(
409 fVolumeTabView
->Selection()))->EnableRescan();
414 ControlsView::EnableCancel()
416 ((VolumeView
*)fVolumeTabView
->ViewForTab(
417 fVolumeTabView
->Selection()))->EnableCancel();
422 ControlsView::FindDeviceFor(dev_t device
, bool invoke
)
424 return fVolumeTabView
->FindDeviceFor(device
, invoke
);