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