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