2 * Copyright 2007-2010 Stephan Aßmus <superstippi@gmx.de>.
3 * All rights reserved. Distributed under the terms of the MIT license.
10 #include <DiskDeviceVisitor.h>
12 #include <GroupLayout.h>
14 #include <LayoutItem.h>
16 #include <PartitioningInfo.h>
19 #include "MainWindow.h"
22 #undef B_TRANSLATION_CONTEXT
23 #define B_TRANSLATION_CONTEXT "DiskView"
25 using BPrivate::HashMap
;
26 using BPrivate::HashKey32
;
28 static const pattern kStripes
= { { 0xc7, 0x8f, 0x1f, 0x3e,
29 0x7c, 0xf8, 0xf1, 0xe3 } };
31 static const float kLayoutInset
= 6;
34 class PartitionView
: public BView
{
36 PartitionView(const char* name
, float weight
, off_t offset
,
37 int32 level
, partition_id id
)
39 BView(name
, B_WILL_DRAW
| B_SUPPORTS_LAYOUT
| B_FULL_UPDATE_ON_RESIZE
),
46 fGroupLayout(new BGroupLayout(B_HORIZONTAL
, kLayoutInset
))
48 SetLayout(fGroupLayout
);
50 SetViewColor(B_TRANSPARENT_COLOR
);
51 rgb_color base
= ui_color(B_PANEL_BACKGROUND_COLOR
);
52 base
= tint_color(base
, B_LIGHTEN_2_TINT
);
53 base
= tint_color(base
, 1 + 0.13 * (level
- 1));
55 SetHighColor(tint_color(base
, B_DARKEN_1_TINT
));
59 font
.SetSize(ceilf(font
.Size() * 0.85));
60 font
.SetRotation(90.0);
63 fGroupLayout
->SetInsets(kLayoutInset
, kLayoutInset
+ font
.Size(),
64 kLayoutInset
, kLayoutInset
);
66 SetExplicitMinSize(BSize(font
.Size() + 6, 30));
69 virtual void MouseDown(BPoint where
)
71 BMessage
message(MSG_SELECTED_PARTITION_ID
);
72 message
.AddInt32("partition_id", fID
);
73 Window()->PostMessage(&message
);
76 virtual void MouseMoved(BPoint where
, uint32 transit
, const BMessage
*)
79 if (Window()->CurrentMessage()->FindInt32("buttons",
80 (int32
*)&buttons
) < B_OK
)
83 _SetMouseOver(buttons
== 0
84 && (transit
== B_ENTERED_VIEW
|| transit
== B_INSIDE_VIEW
));
87 virtual void Draw(BRect updateRect
)
90 float tint
= (B_NO_TINT
+ B_LIGHTEN_1_TINT
) / 2.0;
91 SetHighColor(tint_color(HighColor(), tint
));
92 SetLowColor(tint_color(LowColor(), tint
));
97 SetHighColor(ui_color(B_KEYBOARD_NAVIGATION_COLOR
));
98 StrokeRect(b
, B_SOLID_HIGH
);
100 StrokeRect(b
, B_SOLID_HIGH
);
102 } else if (fLevel
> 0) {
103 StrokeRect(b
, B_SOLID_HIGH
);
107 FillRect(b
, B_SOLID_LOW
);
109 // prevent the text from moving when border width changes
120 // draw the partition label, but only if we have no child partition
123 if (CountChildren() > 0) {
124 font
.SetRotation(0.0);
127 textOffset
= b
.LeftTop();
129 textOffset
.y
+= ceilf(fh
.ascent
);
132 textOffset
= b
.LeftBottom();
133 textOffset
.x
+= ceilf(fh
.ascent
);
136 BString
name(Name());
137 font
.TruncateString(&name
, B_TRUNCATE_END
, width
);
139 SetHighColor(tint_color(LowColor(), B_DARKEN_4_TINT
));
140 DrawString(name
.String(), textOffset
);
158 BGroupLayout
* GroupLayout() const
163 void SetSelected(bool selected
)
165 if (fSelected
== selected
)
168 fSelected
= selected
;
173 void _SetMouseOver(bool mouseOver
)
175 if (fMouseOver
== mouseOver
)
177 fMouseOver
= mouseOver
;
188 BGroupLayout
* fGroupLayout
;
192 class DiskView::PartitionLayout
: public BDiskDeviceVisitor
{
194 PartitionLayout(BView
* view
, SpaceIDMap
& spaceIDMap
)
198 fSelectedPartition(-1),
199 fSpaceIDMap(spaceIDMap
)
203 virtual bool Visit(BDiskDevice
* device
)
206 if (device
->Name() != NULL
&& device
->Name()[0] != '\0')
207 name
= device
->Name();
209 name
= B_TRANSLATE("Device");
211 PartitionView
* view
= new PartitionView(name
, 1.0,
212 device
->Offset(), 0, device
->ID());
213 fViewMap
.Put(device
->ID(), view
);
214 fView
->GetLayout()->AddView(view
);
215 _AddSpaces(device
, view
);
219 virtual bool Visit(BPartition
* partition
, int32 level
)
221 if (!partition
->Parent()
222 || !fViewMap
.ContainsKey(partition
->Parent()->ID()))
225 // calculate size factor within parent frame
226 off_t offset
= partition
->Offset();
227 // off_t parentOffset = partition->Parent()->Offset();
228 off_t size
= partition
->Size();
229 off_t parentSize
= partition
->Parent()->Size();
230 double scale
= (double)size
/ parentSize
;
232 BString name
= partition
->ContentName();
233 if (name
.Length() == 0) {
234 if (partition
->CountChildren() > 0)
235 name
<< partition
->Type();
238 snprintf(buffer
, 64, B_TRANSLATE("Partition %ld"),
243 partition_id id
= partition
->ID();
244 PartitionView
* view
= new PartitionView(name
.String(), scale
, offset
,
246 view
->SetSelected(id
== fSelectedPartition
);
247 PartitionView
* parent
= fViewMap
.Get(partition
->Parent()->ID());
248 BGroupLayout
* layout
= parent
->GroupLayout();
249 layout
->AddView(_FindInsertIndex(view
, layout
), view
, scale
);
251 fViewMap
.Put(partition
->ID(), view
);
252 _AddSpaces(partition
, view
);
257 void SetSelectedPartition(partition_id id
)
259 if (fSelectedPartition
== id
)
262 if (fViewMap
.ContainsKey(fSelectedPartition
)) {
263 PartitionView
* view
= fViewMap
.Get(fSelectedPartition
);
264 view
->SetSelected(false);
267 fSelectedPartition
= id
;
269 if (fViewMap
.ContainsKey(fSelectedPartition
)) {
270 PartitionView
* view
= fViewMap
.Get(fSelectedPartition
);
271 view
->SetSelected(true);
281 void _AddSpaces(BPartition
* partition
, PartitionView
* parentView
)
283 // add any available space on the partition
284 BPartitioningInfo info
;
285 if (partition
->GetPartitioningInfo(&info
) >= B_OK
) {
286 off_t parentSize
= partition
->Size();
290 info
.GetPartitionableSpaceAt(i
, &offset
, &size
) >= B_OK
;
292 // TODO: remove again once Disk Device API is fixed
293 if (!is_valid_partitionable_space(size
))
296 double scale
= (double)size
/ parentSize
;
298 = fSpaceIDMap
.SpaceIDFor(partition
->ID(), offset
);
299 PartitionView
* view
= new PartitionView(B_TRANSLATE("<empty>"),
300 scale
, offset
, parentView
->Level() + 1, id
);
302 fViewMap
.Put(id
, view
);
303 BGroupLayout
* layout
= parentView
->GroupLayout();
304 layout
->AddView(_FindInsertIndex(view
, layout
), view
, scale
);
308 int32
_FindInsertIndex(PartitionView
* view
, BGroupLayout
* layout
) const
310 int32 insertIndex
= 0;
311 int32 count
= layout
->CountItems();
312 for (int32 i
= 0; i
< count
; i
++) {
313 BLayoutItem
* item
= layout
->ItemAt(i
);
316 PartitionView
* sibling
317 = dynamic_cast<PartitionView
*>(item
->View());
318 if (sibling
&& sibling
->Offset() > view
->Offset())
325 typedef HashKey32
<partition_id
> PartitionKey
;
326 typedef HashMap
<PartitionKey
, PartitionView
* > PartitionViewMap
;
329 PartitionViewMap fViewMap
;
330 partition_id fSelectedPartition
;
331 SpaceIDMap
& fSpaceIDMap
;
338 DiskView::DiskView(const BRect
& frame
, uint32 resizeMode
,
339 SpaceIDMap
& spaceIDMap
)
341 Inherited(frame
, "diskview", resizeMode
,
342 B_WILL_DRAW
| B_FULL_UPDATE_ON_RESIZE
),
345 fSpaceIDMap(spaceIDMap
),
346 fPartitionLayout(new PartitionLayout(this, fSpaceIDMap
))
348 BGroupLayout
* layout
= new BGroupLayout(B_HORIZONTAL
, kLayoutInset
);
351 SetViewColor(B_TRANSPARENT_COLOR
);
352 SetHighUIColor(B_PANEL_BACKGROUND_COLOR
, B_DARKEN_2_TINT
);
353 SetLowUIColor(B_PANEL_BACKGROUND_COLOR
, 1.221f
);
355 #ifdef HAIKU_TARGET_PLATFORM_LIBBE_TEST
358 view
= new PartitionView("Disk", scale
, 0, 0, -1);
359 layout
->AddView(view
, scale
);
361 layout
= view
->GroupLayout();
364 view
= new PartitionView("Primary", scale
, 1, 50, -1);
365 layout
->AddView(view
, scale
);
367 view
= new PartitionView("Extended", scale
, 1, 100, -1);
368 layout
->AddView(view
, scale
);
370 layout
= view
->GroupLayout();
373 view
= new PartitionView("Logical", scale
, 2, 200, -1);
374 layout
->AddView(view
, scale
);
377 view
= new PartitionView("Logical", scale
, 2, 250, -1);
378 layout
->AddView(view
, scale
);
381 view
= new PartitionView("Logical", scale
, 2, 290, -1);
382 layout
->AddView(view
, scale
);
385 view
= new PartitionView("Logical", scale
, 2, 420, -1);
386 layout
->AddView(view
, scale
);
391 DiskView::~DiskView()
394 delete fPartitionLayout
;
399 DiskView::Draw(BRect updateRect
)
401 BRect
bounds(Bounds());
406 FillRect(bounds
, kStripes
);
408 const char* helpfulMessage
;
410 helpfulMessage
= B_TRANSLATE("No disk devices have been recognized.");
413 B_TRANSLATE("Select a partition from the list below.");
415 float width
= StringWidth(helpfulMessage
);
418 BRect
messageBounds(bounds
);
419 messageBounds
.InsetBy((bounds
.Width() - width
- fh
.ascent
* 2) / 2.0,
420 (bounds
.Height() - (fh
.ascent
+ fh
.descent
) * 2) / 2.0);
422 FillRoundRect(messageBounds
, 4, 4, B_SOLID_LOW
);
423 rgb_color color
= LowColor();
424 if (color
.Brightness() > 100)
425 color
= tint_color(color
, B_DARKEN_4_TINT
);
427 color
= tint_color(color
, B_LIGHTEN_2_TINT
);
431 textOffset
.x
= messageBounds
.left
+ fh
.ascent
;
432 textOffset
.y
= (messageBounds
.top
+ messageBounds
.bottom
433 - fh
.ascent
- fh
.descent
) / 2 + fh
.ascent
;
434 DrawString(helpfulMessage
, textOffset
);
439 DiskView::SetDiskCount(int32 count
)
446 DiskView::SetDisk(BDiskDevice
* disk
, partition_id selectedPartition
)
453 fPartitionLayout
->SetSelectedPartition(selectedPartition
);
458 DiskView::ForceUpdate()
460 while (BView
* view
= ChildAt(0)) {
465 fPartitionLayout
->Unset();
468 // we need to prepare the disk for modifications, otherwise
469 // we cannot get information about available spaces on the
470 // device or any of its child partitions
471 // TODO: cancelling modifications here is of course undesired
472 // once we hold off the real modifications until an explicit
473 // command to write them to disk...
474 bool prepared
= fDisk
->PrepareModifications() == B_OK
;
475 fDisk
->VisitEachDescendant(fPartitionLayout
);
477 fDisk
->CancelModifications();