xref: /haiku/src/apps/drivesetup/PartitionList.cpp (revision b3de82492af3b6412ffaf7eb87fd6e1995755685)
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 if (partition->CountChildren() > 0) {
207 		SetField(new BStringField(kUnavailableString), kFilesystemColumn);
208 		SetField(new BStringField(kUnavailableString), kVolumeNameColumn);
209 	} else {
210 		SetField(new BStringField(partition->Type()), kFilesystemColumn);
211 		SetField(new BStringField(kUnavailableString), kVolumeNameColumn);
212 	}
213 
214 	if (partition->IsMounted() && partition->GetMountPoint(&path) == B_OK) {
215 		SetField(new BStringField(path.Path()),  kMountedAtColumn);
216 	} else {
217 		SetField(new BStringField(kUnavailableString), kMountedAtColumn);
218 	}
219 
220 	char size[1024];
221 	SetField(new BStringField(string_for_size(partition->Size(), size)),
222 		kSizeColumn);
223 }
224 
225 
226 PartitionListRow::PartitionListRow(partition_id parentID, partition_id id,
227 		off_t offset, off_t size)
228 	: Inherited(),
229 	fPartitionID(id),
230 	fParentID(parentID),
231 	fOffset(offset),
232 	fSize(size)
233 {
234 	// TODO: design icon for spaces on partitions
235 	SetField(new BBitmapStringField(NULL, "-"), kDeviceColumn);
236 
237 	SetField(new BStringField("<empty>"), kFilesystemColumn);
238 	SetField(new BStringField(kUnavailableString), kVolumeNameColumn);
239 
240 	SetField(new BStringField(kUnavailableString), kMountedAtColumn);
241 
242 	char sizeString[1024];
243 	SetField(new BStringField(string_for_size(size, sizeString)), kSizeColumn);
244 }
245 
246 
247 // #pragma mark - PartitionListView
248 
249 
250 PartitionListView::PartitionListView(const BRect& frame, uint32 resizeMode)
251 	: Inherited(frame, "storagelist", resizeMode, 0, B_NO_BORDER, true)
252 {
253 	AddColumn(new PartitionColumn("Device", 150, 50, 500,
254 		B_TRUNCATE_MIDDLE), kDeviceColumn);
255 	AddColumn(new PartitionColumn("File system", 100, 50, 500,
256 		B_TRUNCATE_MIDDLE), kFilesystemColumn);
257 	AddColumn(new PartitionColumn("Volume name", 130, 50, 500,
258 		B_TRUNCATE_MIDDLE), kVolumeNameColumn);
259 	AddColumn(new PartitionColumn("Mounted at", 100, 50, 500,
260 		B_TRUNCATE_MIDDLE), kMountedAtColumn);
261 	AddColumn(new PartitionColumn("Size", 100, 50, 500,
262 		B_TRUNCATE_END, B_ALIGN_RIGHT), kSizeColumn);
263 
264 	SetSortingEnabled(false);
265 }
266 
267 
268 void
269 PartitionListView::AttachedToWindow()
270 {
271 	Inherited::AttachedToWindow();
272 	PartitionColumn::InitTextMargin(ScrollView());
273 }
274 
275 
276 PartitionListRow*
277 PartitionListView::FindRow(partition_id id, PartitionListRow* parent)
278 {
279 	for (int32 i = 0; i < CountRows(parent); i++) {
280 		PartitionListRow* item
281 			= dynamic_cast<PartitionListRow*>(RowAt(i, parent));
282 		if (item != NULL && item->ID() == id)
283 			return item;
284 		if (CountRows(item) > 0) {
285 			// recurse into child rows
286 			item = FindRow(id, item);
287 			if (item)
288 				return item;
289 		}
290 	}
291 
292 	return NULL;
293 }
294 
295 
296 PartitionListRow*
297 PartitionListView::AddPartition(BPartition* partition)
298 {
299 	PartitionListRow* partitionrow = FindRow(partition->ID());
300 
301 	// forget about it if this partition is already in the listview
302 	if (partitionrow != NULL)
303 		return partitionrow;
304 
305 	// create the row for this partition
306 	partitionrow = new PartitionListRow(partition);
307 
308 	// see if this partition has a parent, or should have
309 	// a parent (add it in this case)
310 	PartitionListRow* parent = NULL;
311 	if (partition->Parent() != NULL) {
312 		// check if it is in the listview
313 		parent = FindRow(partition->Parent()->ID());
314 		// If parent of this partition is not yet in the list
315 		if (parent == NULL) {
316 			// add it
317 			parent = AddPartition(partition->Parent());
318 		}
319 	}
320 
321 	// find a proper insertion index based on the on-disk offset
322 	int32 index = _InsertIndexForOffset(parent, partition->Offset());
323 
324 	// add the row, parent may be NULL (add at top level)
325 	AddRow(partitionrow, index, parent);
326 
327 	// make sure the row is initially expanded
328 	ExpandOrCollapse(partitionrow, true);
329 
330 	return partitionrow;
331 }
332 
333 
334 PartitionListRow*
335 PartitionListView::AddSpace(partition_id parentID, partition_id id,
336 	off_t offset, off_t size)
337 {
338 	// the parent should already be in the listview
339 	PartitionListRow* parent = FindRow(parentID);
340 	if (!parent)
341 		return NULL;
342 
343 	// create the row for this partition
344 	PartitionListRow* partitionrow = new PartitionListRow(parentID,
345 		id, offset, size);
346 
347 	// find a proper insertion index based on the on-disk offset
348 	int32 index = _InsertIndexForOffset(parent, offset);
349 
350 	// add the row, parent may be NULL (add at top level)
351 	AddRow(partitionrow, index, parent);
352 
353 	// make sure the row is initially expanded
354 	ExpandOrCollapse(partitionrow, true);
355 
356 	return partitionrow;
357 }
358 
359 
360 int32
361 PartitionListView::_InsertIndexForOffset(PartitionListRow* parent,
362 	off_t offset) const
363 {
364 	int32 index = 0;
365 	int32 count = CountRows(parent);
366 	for (; index < count; index++) {
367 		const PartitionListRow* item
368 			= dynamic_cast<const PartitionListRow*>(RowAt(index, parent));
369 		if (item && item->Offset() > offset)
370 			break;
371 	}
372 	return index;
373 }
374 
375 
376