xref: /haiku/src/apps/drivesetup/PartitionList.cpp (revision 89755088d790ff4fe36f8aa77dacb2bd15507108)
1 /*
2  * Copyright 2006-2008 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 bool
131 PartitionColumn::AcceptsField(const BField* field) const
132 {
133 	return dynamic_cast<const BStringField*>(field) != NULL;
134 }
135 
136 
137 // #pragma mark - PartitionListRow
138 
139 
140 static const char* kUnavailableString = "";
141 
142 enum {
143 	kDeviceColumn,
144 	kFilesystemColumn,
145 	kVolumeNameColumn,
146 	kMountedAtColumn,
147 	kSizeColumn
148 };
149 
150 
151 PartitionListRow::PartitionListRow(BPartition* partition)
152 	: Inherited()
153 	, fPartitionID(partition->ID())
154 	, fParentID(partition->Parent() ? partition->Parent()->ID() : -1)
155 	, fOffset(partition->Offset())
156 	, fSize(partition->Size())
157 {
158 	BPath path;
159 	partition->GetPath(&path);
160 
161 	BBitmap* icon = NULL;
162 	if (partition->IsDevice()) {
163 		icon_size size = B_MINI_ICON;
164 		icon = new BBitmap(BRect(0, 0, size - 1, size - 1), B_RGBA32);
165 		if (partition->GetIcon(icon, size) != B_OK) {
166 			delete icon;
167 			icon = NULL;
168 		}
169 	}
170 
171 	SetField(new BBitmapStringField(icon, path.Path()), kDeviceColumn);
172 
173 	if (partition->ContainsFileSystem()) {
174 		SetField(new BStringField(partition->ContentType()), kFilesystemColumn);
175 		SetField(new BStringField(partition->ContentName()), kVolumeNameColumn);
176 	} else {
177 		SetField(new BStringField(kUnavailableString), kFilesystemColumn);
178 		SetField(new BStringField(kUnavailableString), kVolumeNameColumn);
179 	}
180 
181 	if (partition->IsMounted() && partition->GetMountPoint(&path) == B_OK) {
182 		SetField(new BStringField(path.Path()),  kMountedAtColumn);
183 	} else {
184 		SetField(new BStringField(kUnavailableString), kMountedAtColumn);
185 	}
186 
187 	char size[1024];
188 	SetField(new BStringField(string_for_size(partition->Size(), size)),
189 		kSizeColumn);
190 }
191 
192 
193 PartitionListRow::PartitionListRow(partition_id parentID, partition_id id,
194 		off_t offset, off_t size)
195 	: Inherited()
196 	, fPartitionID(id)
197 	, fParentID(parentID)
198 	, fOffset(offset)
199 	, fSize(size)
200 {
201 	// TODO: design icon for spaces on partitions
202 	SetField(new BBitmapStringField(NULL, "-"), kDeviceColumn);
203 
204 	SetField(new BStringField("<empty>"), kFilesystemColumn);
205 	SetField(new BStringField(kUnavailableString), kVolumeNameColumn);
206 
207 	SetField(new BStringField(kUnavailableString), kMountedAtColumn);
208 
209 	char sizeString[1024];
210 	SetField(new BStringField(string_for_size(size, sizeString)), kSizeColumn);
211 }
212 
213 
214 PartitionListView::PartitionListView(const BRect& frame, uint32 resizeMode)
215 	: Inherited(frame, "storagelist", resizeMode, 0, B_NO_BORDER, true)
216 {
217 	AddColumn(new PartitionColumn("Device", 150, 50, 500,
218 		B_TRUNCATE_MIDDLE), kDeviceColumn);
219 	AddColumn(new PartitionColumn("Filesystem", 100, 50, 500,
220 		B_TRUNCATE_MIDDLE), kFilesystemColumn);
221 	AddColumn(new PartitionColumn("Volume Name", 130, 50, 500,
222 		B_TRUNCATE_MIDDLE), kVolumeNameColumn);
223 	AddColumn(new PartitionColumn("Mounted At", 100, 50, 500,
224 		B_TRUNCATE_MIDDLE), kMountedAtColumn);
225 	AddColumn(new PartitionColumn("Size", 100, 50, 500,
226 		B_TRUNCATE_END, B_ALIGN_RIGHT), kSizeColumn);
227 
228 	SetSortingEnabled(false);
229 }
230 
231 
232 PartitionListRow*
233 PartitionListView::FindRow(partition_id id, PartitionListRow* parent)
234 {
235 	for (int32 i = 0; i < CountRows(parent); i++) {
236 		PartitionListRow* item
237 			= dynamic_cast<PartitionListRow*>(RowAt(i, parent));
238 		if (item != NULL && item->ID() == id)
239 			return item;
240 		if (CountRows(item) > 0) {
241 			// recurse into child rows
242 			item = FindRow(id, item);
243 			if (item)
244 				return item;
245 		}
246 	}
247 
248 	return NULL;
249 }
250 
251 
252 PartitionListRow*
253 PartitionListView::AddPartition(BPartition* partition)
254 {
255 	PartitionListRow* partitionrow = FindRow(partition->ID());
256 
257 	// forget about it if this partition is already in the listview
258 	if (partitionrow != NULL)
259 		return partitionrow;
260 
261 	// create the row for this partition
262 	partitionrow = new PartitionListRow(partition);
263 
264 	// see if this partition has a parent, or should have
265 	// a parent (add it in this case)
266 	PartitionListRow* parent = NULL;
267 	if (partition->Parent() != NULL) {
268 		// check if it is in the listview
269 		parent = FindRow(partition->Parent()->ID());
270 		// If parent of this partition is not yet in the list
271 		if (parent == NULL) {
272 			// add it
273 			parent = AddPartition(partition->Parent());
274 		}
275 	}
276 
277 	// find a proper insertion index based on the on-disk offset
278 	int32 index = _InsertIndexForOffset(parent, partition->Offset());
279 
280 	// add the row, parent may be NULL (add at top level)
281 	AddRow(partitionrow, index, parent);
282 
283 	// make sure the row is initially expanded
284 	ExpandOrCollapse(partitionrow, true);
285 
286 	return partitionrow;
287 }
288 
289 
290 PartitionListRow*
291 PartitionListView::AddSpace(partition_id parentID, partition_id id,
292 	off_t offset, off_t size)
293 {
294 	// the parent should already be in the listview
295 	PartitionListRow* parent = FindRow(parentID);
296 	if (!parent)
297 		return NULL;
298 
299 	// create the row for this partition
300 	PartitionListRow* partitionrow = new PartitionListRow(parentID,
301 		id, offset, size);
302 
303 	// find a proper insertion index based on the on-disk offset
304 	int32 index = _InsertIndexForOffset(parent, offset);
305 
306 	// add the row, parent may be NULL (add at top level)
307 	AddRow(partitionrow, index, parent);
308 
309 	// make sure the row is initially expanded
310 	ExpandOrCollapse(partitionrow, true);
311 
312 	return partitionrow;
313 }
314 
315 
316 int32
317 PartitionListView::_InsertIndexForOffset(PartitionListRow* parent,
318 	off_t offset) const
319 {
320 	int32 index = 0;
321 	int32 count = CountRows(parent);
322 	for (; index < count; index++) {
323 		const PartitionListRow* item
324 			= dynamic_cast<const PartitionListRow*>(RowAt(index, parent));
325 		if (item && item->Offset() > offset)
326 			break;
327 	}
328 	return index;
329 }
330 
331 
332