xref: /haiku/src/apps/drivesetup/PartitionList.cpp (revision 3be9edf8da228afd9fec0390f408c964766122aa)
1 /*
2  * Copyright 2006-2009 Haiku Inc. All rights reserved.
3  * Distributed under the terms of the MIT license.
4  *
5  * Authors:
6  *		Ithamar R. Adema <ithamar@unet.nl>
7  *		James Urquhart
8  *		Stephan Aßmus <superstippi@gmx.de>
9  */
10 #include "PartitionList.h"
11 #include "Support.h"
12 
13 #include <ColumnTypes.h>
14 #include <Path.h>
15 
16 
17 // #pragma mark - BBitmapStringField
18 
19 
20 BBitmapStringField::BBitmapStringField(BBitmap* bitmap, const char* string)
21 	: Inherited(string),
22 	fBitmap(bitmap)
23 {
24 }
25 
26 
27 BBitmapStringField::~BBitmapStringField()
28 {
29 	delete fBitmap;
30 }
31 
32 
33 void
34 BBitmapStringField::SetBitmap(BBitmap* bitmap)
35 {
36 	delete fBitmap;
37 	fBitmap = bitmap;
38 	// TODO: cause a redraw?
39 }
40 
41 
42 // #pragma mark - PartitionColumn
43 
44 
45 float PartitionColumn::sTextMargin = 0.0;
46 
47 
48 PartitionColumn::PartitionColumn(const char* title, float width, float minWidth,
49 		float maxWidth, uint32 truncateMode, alignment align)
50 	: Inherited(title, width, minWidth, maxWidth, align),
51 	fTruncateMode(truncateMode)
52 {
53 	SetWantsEvents(true);
54 }
55 
56 
57 void
58 PartitionColumn::DrawField(BField* field, BRect rect, BView* parent)
59 {
60 	BBitmapStringField* bitmapField
61 		= dynamic_cast<BBitmapStringField*>(field);
62 	BStringField* stringField = dynamic_cast<BStringField*>(field);
63 
64 	if (bitmapField) {
65 		const BBitmap* bitmap = bitmapField->Bitmap();
66 
67 		// figure out the placement
68 		float x = 0.0;
69 		BRect r = bitmap ? bitmap->Bounds() : BRect(0, 0, 15, 15);
70 		float y = rect.top + ((rect.Height() - r.Height()) / 2);
71 		float width = 0.0;
72 
73 		switch (Alignment()) {
74 			default:
75 			case B_ALIGN_LEFT:
76 			case B_ALIGN_CENTER:
77 				x = rect.left + sTextMargin;
78 				width = rect.right - (x + r.Width()) - (2 * sTextMargin);
79 				r.Set(x + r.Width(), rect.top, rect.right - width, rect.bottom);
80 				break;
81 
82 			case B_ALIGN_RIGHT:
83 				x = rect.right - sTextMargin - r.Width();
84 				width = (x - rect.left - (2 * sTextMargin));
85 				r.Set(rect.left, rect.top, rect.left + width, rect.bottom);
86 				break;
87 		}
88 
89 		if (width != bitmapField->Width()) {
90 			BString truncatedString(bitmapField->String());
91 			parent->TruncateString(&truncatedString, fTruncateMode, width + 2);
92 			bitmapField->SetClippedString(truncatedString.String());
93 			bitmapField->SetWidth(width);
94 		}
95 
96 		// draw the bitmap
97 		if (bitmap) {
98 			parent->SetDrawingMode(B_OP_ALPHA);
99 			parent->DrawBitmap(bitmap, BPoint(x, y));
100 			parent->SetDrawingMode(B_OP_OVER);
101 		}
102 
103 		// draw the string
104 		DrawString(bitmapField->ClippedString(), parent, r);
105 
106 	} else if (stringField) {
107 
108 		float width = rect.Width() - (2 * sTextMargin);
109 
110 		if (width != stringField->Width()) {
111 			BString truncatedString(stringField->String());
112 
113 			parent->TruncateString(&truncatedString, fTruncateMode, width + 2);
114 			stringField->SetClippedString(truncatedString.String());
115 			stringField->SetWidth(width);
116 		}
117 
118 		DrawString(stringField->ClippedString(), parent, rect);
119 	}
120 }
121 
122 
123 float
124 PartitionColumn::GetPreferredWidth(BField *_field, BView* parent) const
125 {
126 	BBitmapStringField* bitmapField
127 		= dynamic_cast<BBitmapStringField*>(_field);
128 	BStringField* stringField = dynamic_cast<BStringField*>(_field);
129 
130 	float parentWidth = Inherited::GetPreferredWidth(_field, parent);
131 	float width = 0.0;
132 
133 	if (bitmapField) {
134 		const BBitmap* bitmap = bitmapField->Bitmap();
135 		BFont font;
136 		parent->GetFont(&font);
137 		width = font.StringWidth(bitmapField->String()) + 3 * sTextMargin;
138 		if (bitmap)
139 			width += bitmap->Bounds().Width();
140 		else
141 			width += 16;
142 	} else if (stringField) {
143 		BFont font;
144 		parent->GetFont(&font);
145 		width = font.StringWidth(stringField->String()) + 2 * sTextMargin;
146 	}
147 	return max_c(width, parentWidth);
148 }
149 
150 
151 bool
152 PartitionColumn::AcceptsField(const BField* field) const
153 {
154 	return dynamic_cast<const BStringField*>(field) != NULL;
155 }
156 
157 
158 void
159 PartitionColumn::InitTextMargin(BView* parent)
160 {
161 	BFont font;
162 	parent->GetFont(&font);
163 	sTextMargin = ceilf(font.Size() * 0.8);
164 }
165 
166 
167 // #pragma mark - PartitionListRow
168 
169 
170 static const char* kUnavailableString = "";
171 
172 enum {
173 	kDeviceColumn,
174 	kFilesystemColumn,
175 	kVolumeNameColumn,
176 	kMountedAtColumn,
177 	kSizeColumn
178 };
179 
180 
181 PartitionListRow::PartitionListRow(BPartition* partition)
182 	: Inherited(),
183 	fPartitionID(partition->ID()),
184 	fParentID(partition->Parent() ? partition->Parent()->ID() : -1),
185 	fOffset(partition->Offset()),
186 	fSize(partition->Size())
187 {
188 	BPath path;
189 	partition->GetPath(&path);
190 
191 	BBitmap* icon = NULL;
192 	if (partition->IsDevice()) {
193 		icon_size size = B_MINI_ICON;
194 		icon = new BBitmap(BRect(0, 0, size - 1, size - 1), B_RGBA32);
195 		if (partition->GetIcon(icon, size) != B_OK) {
196 			delete icon;
197 			icon = NULL;
198 		}
199 	}
200 
201 	SetField(new BBitmapStringField(icon, path.Path()), kDeviceColumn);
202 
203 	if (partition->ContainsFileSystem()) {
204 		SetField(new BStringField(partition->ContentType()), kFilesystemColumn);
205 		SetField(new BStringField(partition->ContentName()), kVolumeNameColumn);
206 	} else {
207 		SetField(new BStringField(kUnavailableString), kFilesystemColumn);
208 		SetField(new BStringField(kUnavailableString), kVolumeNameColumn);
209 	}
210 
211 	if (partition->IsMounted() && partition->GetMountPoint(&path) == B_OK) {
212 		SetField(new BStringField(path.Path()),  kMountedAtColumn);
213 	} else {
214 		SetField(new BStringField(kUnavailableString), kMountedAtColumn);
215 	}
216 
217 	char size[1024];
218 	SetField(new BStringField(string_for_size(partition->Size(), size)),
219 		kSizeColumn);
220 }
221 
222 
223 PartitionListRow::PartitionListRow(partition_id parentID, partition_id id,
224 		off_t offset, off_t size)
225 	: Inherited(),
226 	fPartitionID(id),
227 	fParentID(parentID),
228 	fOffset(offset),
229 	fSize(size)
230 {
231 	// TODO: design icon for spaces on partitions
232 	SetField(new BBitmapStringField(NULL, "-"), kDeviceColumn);
233 
234 	SetField(new BStringField("<empty>"), kFilesystemColumn);
235 	SetField(new BStringField(kUnavailableString), kVolumeNameColumn);
236 
237 	SetField(new BStringField(kUnavailableString), kMountedAtColumn);
238 
239 	char sizeString[1024];
240 	SetField(new BStringField(string_for_size(size, sizeString)), kSizeColumn);
241 }
242 
243 
244 // #pragma mark - PartitionListView
245 
246 
247 PartitionListView::PartitionListView(const BRect& frame, uint32 resizeMode)
248 	: Inherited(frame, "storagelist", resizeMode, 0, B_NO_BORDER, true)
249 {
250 	AddColumn(new PartitionColumn("Device", 150, 50, 500,
251 		B_TRUNCATE_MIDDLE), kDeviceColumn);
252 	AddColumn(new PartitionColumn("Filesystem", 100, 50, 500,
253 		B_TRUNCATE_MIDDLE), kFilesystemColumn);
254 	AddColumn(new PartitionColumn("Volume Name", 130, 50, 500,
255 		B_TRUNCATE_MIDDLE), kVolumeNameColumn);
256 	AddColumn(new PartitionColumn("Mounted At", 100, 50, 500,
257 		B_TRUNCATE_MIDDLE), kMountedAtColumn);
258 	AddColumn(new PartitionColumn("Size", 100, 50, 500,
259 		B_TRUNCATE_END, B_ALIGN_RIGHT), kSizeColumn);
260 
261 	SetSortingEnabled(false);
262 }
263 
264 
265 void
266 PartitionListView::AttachedToWindow()
267 {
268 	Inherited::AttachedToWindow();
269 	PartitionColumn::InitTextMargin(ScrollView());
270 }
271 
272 
273 PartitionListRow*
274 PartitionListView::FindRow(partition_id id, PartitionListRow* parent)
275 {
276 	for (int32 i = 0; i < CountRows(parent); i++) {
277 		PartitionListRow* item
278 			= dynamic_cast<PartitionListRow*>(RowAt(i, parent));
279 		if (item != NULL && item->ID() == id)
280 			return item;
281 		if (CountRows(item) > 0) {
282 			// recurse into child rows
283 			item = FindRow(id, item);
284 			if (item)
285 				return item;
286 		}
287 	}
288 
289 	return NULL;
290 }
291 
292 
293 PartitionListRow*
294 PartitionListView::AddPartition(BPartition* partition)
295 {
296 	PartitionListRow* partitionrow = FindRow(partition->ID());
297 
298 	// forget about it if this partition is already in the listview
299 	if (partitionrow != NULL)
300 		return partitionrow;
301 
302 	// create the row for this partition
303 	partitionrow = new PartitionListRow(partition);
304 
305 	// see if this partition has a parent, or should have
306 	// a parent (add it in this case)
307 	PartitionListRow* parent = NULL;
308 	if (partition->Parent() != NULL) {
309 		// check if it is in the listview
310 		parent = FindRow(partition->Parent()->ID());
311 		// If parent of this partition is not yet in the list
312 		if (parent == NULL) {
313 			// add it
314 			parent = AddPartition(partition->Parent());
315 		}
316 	}
317 
318 	// find a proper insertion index based on the on-disk offset
319 	int32 index = _InsertIndexForOffset(parent, partition->Offset());
320 
321 	// add the row, parent may be NULL (add at top level)
322 	AddRow(partitionrow, index, parent);
323 
324 	// make sure the row is initially expanded
325 	ExpandOrCollapse(partitionrow, true);
326 
327 	return partitionrow;
328 }
329 
330 
331 PartitionListRow*
332 PartitionListView::AddSpace(partition_id parentID, partition_id id,
333 	off_t offset, off_t size)
334 {
335 	// the parent should already be in the listview
336 	PartitionListRow* parent = FindRow(parentID);
337 	if (!parent)
338 		return NULL;
339 
340 	// create the row for this partition
341 	PartitionListRow* partitionrow = new PartitionListRow(parentID,
342 		id, offset, size);
343 
344 	// find a proper insertion index based on the on-disk offset
345 	int32 index = _InsertIndexForOffset(parent, offset);
346 
347 	// add the row, parent may be NULL (add at top level)
348 	AddRow(partitionrow, index, parent);
349 
350 	// make sure the row is initially expanded
351 	ExpandOrCollapse(partitionrow, true);
352 
353 	return partitionrow;
354 }
355 
356 
357 int32
358 PartitionListView::_InsertIndexForOffset(PartitionListRow* parent,
359 	off_t offset) const
360 {
361 	int32 index = 0;
362 	int32 count = CountRows(parent);
363 	for (; index < count; index++) {
364 		const PartitionListRow* item
365 			= dynamic_cast<const PartitionListRow*>(RowAt(index, parent));
366 		if (item && item->Offset() > offset)
367 			break;
368 	}
369 	return index;
370 }
371 
372 
373