1/*
2Open Tracker License
3
4Terms and Conditions
5
6Copyright (c) 1991-2000, Be Incorporated. All rights reserved.
7
8Permission is hereby granted, free of charge, to any person obtaining a copy of
9this software and associated documentation files (the "Software"), to deal in
10the Software without restriction, including without limitation the rights to
11use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
12of the Software, and to permit persons to whom the Software is furnished to do
13so, subject to the following conditions:
14
15The above copyright notice and this permission notice applies to all licensees
16and shall be included in all copies or substantial portions of the Software.
17
18THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF TITLE, MERCHANTABILITY,
20FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21BE INCORPORATED BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
22AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION
23WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24
25Except as contained in this notice, the name of Be Incorporated shall not be
26used in advertising or otherwise to promote the sale, use or other dealings in
27this Software without prior written authorization from Be Incorporated.
28
29Tracker(TM), Be(R), BeOS(R), and BeIA(TM) are trademarks or registered trademarks
30of Be Incorporated in the United States and other countries. Other brand product
31names are registered trademarks or trademarks of their respective holders.
32All rights reserved.
33*/
34
35
36#include <Debug.h>
37#include <AppDefs.h>
38#include <InterfaceDefs.h>
39
40#include "Attributes.h"
41#include "Commands.h"
42#include "PoseView.h"
43#include "Utilities.h"
44#include "ViewState.h"
45
46#include <new>
47#include <string.h>
48#include <stdlib.h>
49
50
51const char* kColumnVersionName = "BColumn:version";
52const char* kColumnTitleName = "BColumn:fTitle";
53const char* kColumnOffsetName = "BColumn:fOffset";
54const char* kColumnWidthName = "BColumn:fWidth";
55const char* kColumnAlignmentName = "BColumn:fAlignment";
56const char* kColumnAttrName = "BColumn:fAttrName";
57const char* kColumnAttrHashName = "BColumn:fAttrHash";
58const char* kColumnAttrTypeName = "BColumn:fAttrType";
59const char* kColumnDisplayAsName = "BColumn:fDisplayAs";
60const char* kColumnStatFieldName = "BColumn:fStatField";
61const char* kColumnEditableName = "BColumn:fEditable";
62
63const char* kViewStateVersionName = "ViewState:version";
64const char* kViewStateViewModeName = "ViewState:fViewMode";
65const char* kViewStateLastIconModeName = "ViewState:fLastIconMode";
66const char* kViewStateListOriginName = "ViewState:fListOrigin";
67const char* kViewStateIconOriginName = "ViewState:fIconOrigin";
68const char* kViewStatePrimarySortAttrName = "ViewState:fPrimarySortAttr";
69const char* kViewStatePrimarySortTypeName = "ViewState:fPrimarySortType";
70const char* kViewStateSecondarySortAttrName = "ViewState:fSecondarySortAttr";
71const char* kViewStateSecondarySortTypeName = "ViewState:fSecondarySortType";
72const char* kViewStateReverseSortName = "ViewState:fReverseSort";
73const char* kViewStateIconSizeName = "ViewState:fIconSize";
74const char* kViewStateLastIconSizeName = "ViewState:fLastIconSize";
75
76
77static const int32 kColumnStateMinArchiveVersion = 21;
78	// bump version when layout changes
79
80
81//	#pragma mark - BColumn
82
83
84BColumn::BColumn(const char* title, float width,
85	alignment align, const char* attributeName, uint32 attrType,
86	const char* displayAs, bool statField, bool editable)
87{
88	_Init(title, width, align, attributeName, attrType, displayAs,
89		statField, editable);
90}
91
92
93BColumn::BColumn(const char* title, float width,
94	alignment align, const char* attributeName, uint32 attrType,
95	bool statField, bool editable)
96{
97	_Init(title, width, align, attributeName, attrType, NULL,
98		statField, editable);
99}
100
101
102BColumn::~BColumn()
103{
104}
105
106
107BColumn::BColumn(BMallocIO* stream, int32 version, bool endianSwap)
108{
109	StringFromStream(&fTitle, stream, endianSwap);
110	stream->Read(&fOffset, sizeof(float));
111	stream->Read(&fWidth, sizeof(float));
112	stream->Read(&fAlignment, sizeof(alignment));
113	StringFromStream(&fAttrName, stream, endianSwap);
114	stream->Read(&fAttrHash, sizeof(uint32));
115	stream->Read(&fAttrType, sizeof(uint32));
116	stream->Read(&fStatField, sizeof(bool));
117	stream->Read(&fEditable, sizeof(bool));
118	if (version == kColumnStateArchiveVersion)
119		StringFromStream(&fDisplayAs, stream, endianSwap);
120
121	if (endianSwap) {
122		PRINT(("endian swapping column\n"));
123		fOffset = B_SWAP_FLOAT(fOffset);
124		fWidth = B_SWAP_FLOAT(fWidth);
125		STATIC_ASSERT(sizeof(alignment) == sizeof(int32));
126		fAlignment = (alignment)B_SWAP_INT32(fAlignment);
127		fAttrHash = B_SWAP_INT32(fAttrHash);
128		fAttrType = B_SWAP_INT32(fAttrType);
129	}
130
131	fOffset = ceilf(fOffset * _Scale());
132	fWidth = ceilf(fWidth * _Scale());
133}
134
135
136BColumn::BColumn(const BMessage &message, int32 index)
137{
138	if (message.FindString(kColumnTitleName, index, &fTitle) != B_OK)
139		fTitle.SetTo(B_EMPTY_STRING);
140
141	if (message.FindFloat(kColumnOffsetName, index, &fOffset) != B_OK)
142		fOffset = -1.0f;
143	else
144		fOffset = ceilf(fOffset * _Scale());
145
146	if (message.FindFloat(kColumnWidthName, index, &fWidth) != B_OK)
147		fWidth = -1.0f;
148	else
149		fWidth = ceilf(fWidth * _Scale());
150
151	if (message.FindInt32(kColumnAlignmentName, index, (int32*)&fAlignment)
152			!= B_OK) {
153		fAlignment = B_ALIGN_LEFT;
154	}
155
156	if (message.FindString(kColumnAttrName, index, &fAttrName) != B_OK)
157		fAttrName = BString(B_EMPTY_STRING);
158
159	if (message.FindInt32(kColumnAttrHashName, index, (int32*)&fAttrHash)
160			!= B_OK) {
161		fAttrHash = 0;
162	}
163
164	if (message.FindInt32(kColumnAttrTypeName, index, (int32*)&fAttrType)
165			!= B_OK) {
166		fAttrType = 0;
167	}
168
169	if (message.FindString(kColumnDisplayAsName, index, &fDisplayAs) != B_OK)
170		fDisplayAs.SetTo(B_EMPTY_STRING);
171
172	if (message.FindBool(kColumnStatFieldName, index, &fStatField) != B_OK)
173		fStatField = false;
174
175	if (message.FindBool(kColumnEditableName, index, &fEditable) != B_OK)
176		fEditable = false;
177}
178
179
180void
181BColumn::_Init(const char* title, float width,
182	alignment align, const char* attributeName, uint32 attrType,
183	const char* displayAs, bool statField, bool editable)
184{
185	fTitle = title;
186	fAttrName = attributeName;
187	fDisplayAs = displayAs;
188	fOffset = -1.0f;
189	fWidth = width * _Scale();
190	fAlignment = align;
191	fAttrHash = AttrHashString(attributeName, attrType);
192	fAttrType = attrType;
193	fStatField = statField;
194	fEditable = editable;
195}
196
197
198/* static */ float
199BColumn::_Scale()
200{
201	return (be_plain_font->Size() / 12.0f);
202}
203
204
205BColumn*
206BColumn::InstantiateFromStream(BMallocIO* stream, bool endianSwap)
207{
208	// compare stream header in canonical form
209
210	// we can't use ValidateStream(), as we preserve backwards compatibility
211	int32 version;
212	uint32 key;
213	if (stream->Read(&key, sizeof(uint32)) <= 0
214		|| stream->Read(&version, sizeof(int32)) <=0)
215		return 0;
216
217	if (endianSwap) {
218		key = SwapUInt32(key);
219		version = SwapInt32(version);
220	}
221
222	if (key != AttrHashString("BColumn", B_OBJECT_TYPE)
223		|| version < kColumnStateMinArchiveVersion)
224		return 0;
225
226//	PRINT(("instantiating column, %s\n", endianSwap ? "endian swapping," : ""));
227	return _Sanitize(new (std::nothrow) BColumn(stream, version, endianSwap));
228}
229
230
231BColumn*
232BColumn::InstantiateFromMessage(const BMessage &message, int32 index)
233{
234	int32 version = kColumnStateArchiveVersion;
235	int32 messageVersion;
236
237	if (message.FindInt32(kColumnVersionName, index, &messageVersion) != B_OK)
238		return NULL;
239
240	if (version != messageVersion)
241		return NULL;
242
243	return _Sanitize(new (std::nothrow) BColumn(message, index));
244}
245
246
247void
248BColumn::ArchiveToStream(BMallocIO* stream) const
249{
250	// write class identifier and version info
251	uint32 key = AttrHashString("BColumn", B_OBJECT_TYPE);
252	stream->Write(&key, sizeof(uint32));
253	int32 version = kColumnStateArchiveVersion;
254	stream->Write(&version, sizeof(int32));
255
256//	PRINT(("ArchiveToStream column, key %x, version %d\n", key, version));
257
258	const float offset = floorf(fOffset / _Scale()),
259		width = floorf(fWidth / _Scale());
260
261	StringToStream(&fTitle, stream);
262	stream->Write(&offset, sizeof(float));
263	stream->Write(&width, sizeof(float));
264	stream->Write(&fAlignment, sizeof(alignment));
265	StringToStream(&fAttrName, stream);
266	stream->Write(&fAttrHash, sizeof(uint32));
267	stream->Write(&fAttrType, sizeof(uint32));
268	stream->Write(&fStatField, sizeof(bool));
269	stream->Write(&fEditable, sizeof(bool));
270	StringToStream(&fDisplayAs, stream);
271}
272
273
274void
275BColumn::ArchiveToMessage(BMessage &message) const
276{
277	const float offset = floorf(fOffset / _Scale()),
278		width = floorf(fWidth / _Scale());
279
280	message.AddInt32(kColumnVersionName, kColumnStateArchiveVersion);
281
282	message.AddString(kColumnTitleName, fTitle);
283	message.AddFloat(kColumnOffsetName, offset);
284	message.AddFloat(kColumnWidthName, width);
285	message.AddInt32(kColumnAlignmentName, fAlignment);
286	message.AddString(kColumnAttrName, fAttrName);
287	message.AddInt32(kColumnAttrHashName, static_cast<int32>(fAttrHash));
288	message.AddInt32(kColumnAttrTypeName, static_cast<int32>(fAttrType));
289	message.AddString(kColumnDisplayAsName, fDisplayAs.String());
290	message.AddBool(kColumnStatFieldName, fStatField);
291	message.AddBool(kColumnEditableName, fEditable);
292}
293
294
295BColumn*
296BColumn::_Sanitize(BColumn* column)
297{
298	if (column == NULL)
299		return NULL;
300
301	// sanity-check the resulting column
302	if (column->fTitle.Length() > 500
303		|| column->fOffset < 0
304		|| column->fOffset > 10000
305		|| column->fWidth < 0
306		|| column->fWidth > 10000
307		|| (int32)column->fAlignment < B_ALIGN_LEFT
308		|| (int32)column->fAlignment > B_ALIGN_CENTER
309		|| column->fAttrName.Length() > 500) {
310		PRINT(("column data not valid\n"));
311		delete column;
312		return NULL;
313	}
314#if DEBUG
315// TODO: Whatever this is supposed to mean, fix it.
316//	else if (endianSwap)
317//		PRINT(("Instantiated foreign column ok\n"));
318#endif
319
320	return column;
321}
322
323
324//	#pragma mark - BViewState
325
326
327BViewState::BViewState()
328{
329	_Init();
330	_StorePreviousState();
331}
332
333
334BViewState::BViewState(BMallocIO* stream, bool endianSwap)
335{
336	_Init();
337	stream->Read(&fViewMode, sizeof(uint32));
338	stream->Read(&fLastIconMode, sizeof(uint32));
339	stream->Read(&fListOrigin, sizeof(BPoint));
340	stream->Read(&fIconOrigin, sizeof(BPoint));
341	stream->Read(&fPrimarySortAttr, sizeof(uint32));
342	stream->Read(&fPrimarySortType, sizeof(uint32));
343	stream->Read(&fSecondarySortAttr, sizeof(uint32));
344	stream->Read(&fSecondarySortType, sizeof(uint32));
345	stream->Read(&fReverseSort, sizeof(bool));
346	stream->Read(&fIconSize, sizeof(uint32));
347	stream->Read(&fLastIconSize, sizeof(uint32));
348
349	if (endianSwap) {
350		PRINT(("endian swapping view state\n"));
351		fViewMode = B_SWAP_INT32(fViewMode);
352		fLastIconMode = B_SWAP_INT32(fLastIconMode);
353		fIconSize = B_SWAP_INT32(fIconSize);
354		fLastIconSize = B_SWAP_INT32(fLastIconSize);
355		swap_data(B_POINT_TYPE, &fListOrigin,
356			sizeof(fListOrigin), B_SWAP_ALWAYS);
357		swap_data(B_POINT_TYPE, &fIconOrigin,
358			sizeof(fIconOrigin), B_SWAP_ALWAYS);
359		fPrimarySortAttr = B_SWAP_INT32(fPrimarySortAttr);
360		fSecondarySortAttr = B_SWAP_INT32(fSecondarySortAttr);
361		fPrimarySortType = B_SWAP_INT32(fPrimarySortType);
362		fSecondarySortType = B_SWAP_INT32(fSecondarySortType);
363	}
364
365	_StorePreviousState();
366	_Sanitize(this, true);
367}
368
369
370BViewState::BViewState(const BMessage &message)
371{
372	_Init();
373	message.FindInt32(kViewStateViewModeName, (int32*)&fViewMode);
374	message.FindInt32(kViewStateLastIconModeName, (int32*)&fLastIconMode);
375	message.FindInt32(kViewStateLastIconSizeName,(int32*)&fLastIconSize);
376	message.FindInt32(kViewStateIconSizeName, (int32*)&fIconSize);
377	message.FindPoint(kViewStateListOriginName, &fListOrigin);
378	message.FindPoint(kViewStateIconOriginName, &fIconOrigin);
379	message.FindInt32(kViewStatePrimarySortAttrName,
380		(int32*)&fPrimarySortAttr);
381	message.FindInt32(kViewStatePrimarySortTypeName,
382		(int32*)&fPrimarySortType);
383	message.FindInt32(kViewStateSecondarySortAttrName,
384		(int32*)&fSecondarySortAttr);
385	message.FindInt32(kViewStateSecondarySortTypeName,
386		(int32*)&fSecondarySortType);
387	message.FindBool(kViewStateReverseSortName, &fReverseSort);
388
389	_StorePreviousState();
390	_Sanitize(this, true);
391}
392
393
394void
395BViewState::ArchiveToStream(BMallocIO* stream)
396{
397	_ArchiveToStream(stream);
398	_StorePreviousState();
399}
400
401
402void
403BViewState::ArchiveToMessage(BMessage &message)
404{
405	_ArchiveToMessage(message);
406	_StorePreviousState();
407}
408
409
410BViewState*
411BViewState::InstantiateFromStream(BMallocIO* stream, bool endianSwap)
412{
413	// compare stream header in canonical form
414	uint32 key = AttrHashString("BViewState", B_OBJECT_TYPE);
415	int32 version = kViewStateArchiveVersion;
416
417	if (endianSwap) {
418		key = SwapUInt32(key);
419		version = SwapInt32(version);
420	}
421
422	if (!ValidateStream(stream, key, version))
423		return NULL;
424
425	return _Sanitize(new (std::nothrow) BViewState(stream, endianSwap));
426}
427
428
429BViewState*
430BViewState::InstantiateFromMessage(const BMessage &message)
431{
432	int32 version = kViewStateArchiveVersion;
433
434	int32 messageVersion;
435	if (message.FindInt32(kViewStateVersionName, &messageVersion) != B_OK)
436		return NULL;
437
438	if (version != messageVersion)
439		return NULL;
440
441	return _Sanitize(new (std::nothrow) BViewState(message));
442}
443
444
445void
446BViewState::_Init()
447{
448	fViewMode = kListMode;
449	fLastIconMode = 0;
450	fIconSize = B_LARGE_ICON;
451	fLastIconSize = B_LARGE_ICON;
452	fListOrigin.Set(0, 0);
453	fIconOrigin.Set(0, 0);
454	fPrimarySortAttr = AttrHashString(kAttrStatName, B_STRING_TYPE);
455	fPrimarySortType = B_STRING_TYPE;
456	fSecondarySortAttr = 0;
457	fSecondarySortType = 0;
458	fReverseSort = false;
459}
460
461
462void
463BViewState::_StorePreviousState()
464{
465	fPreviousViewMode = fViewMode;
466	fPreviousLastIconMode = fLastIconMode;
467	fPreviousIconSize = fIconSize;
468	fPreviousLastIconSize = fLastIconSize;
469	fPreviousListOrigin = fListOrigin;
470	fPreviousIconOrigin = fIconOrigin;
471	fPreviousPrimarySortAttr = fPrimarySortAttr;
472	fPreviousSecondarySortAttr = fSecondarySortAttr;
473	fPreviousPrimarySortType = fPrimarySortType;
474	fPreviousSecondarySortType = fSecondarySortType;
475	fPreviousReverseSort = fReverseSort;
476}
477
478
479BViewState*
480BViewState::_Sanitize(BViewState* state, bool fixOnly)
481{
482	if (state == NULL)
483		return NULL;
484
485	if (state->fViewMode == kListMode) {
486		if (state->fListOrigin.x < 0)
487			state->fListOrigin.x = 0;
488
489		if (state->fListOrigin.y < 0)
490			state->fListOrigin.y = 0;
491	}
492	if (state->fIconSize < 16)
493		state->fIconSize = 16;
494
495	if (state->fIconSize > 128)
496		state->fIconSize = 128;
497
498	if (state->fLastIconSize < 16)
499		state->fLastIconSize = 16;
500
501	if (state->fLastIconSize > 128)
502		state->fLastIconSize = 128;
503
504	if (fixOnly)
505		return state;
506
507	// do a sanity check here
508	if ((state->fViewMode != kListMode
509			&& state->fViewMode != kIconMode
510			&& state->fViewMode != kMiniIconMode
511			&& state->fViewMode != 0)
512		|| (state->fLastIconMode != kListMode
513			&& state->fLastIconMode != kIconMode
514			&& state->fLastIconMode != kMiniIconMode
515			&& state->fLastIconMode != 0)) {
516		PRINT(("Bad data instantiating ViewState, view mode %" B_PRIx32
517			", lastIconMode %" B_PRIx32 "\n", state->fViewMode,
518			state->fLastIconMode));
519
520		delete state;
521		return NULL;
522	}
523#if DEBUG
524// TODO: Whatever this is supposed to mean, fix it.
525//	else if (endianSwap)
526//		PRINT(("Instantiated foreign view state ok\n"));
527#endif
528
529	return state;
530}
531
532
533void
534BViewState::_ArchiveToStream(BMallocIO* stream) const
535{
536	// write class identifier and verison info
537	uint32 key = AttrHashString("BViewState", B_OBJECT_TYPE);
538	stream->Write(&key, sizeof(key));
539	int32 version = kViewStateArchiveVersion;
540	stream->Write(&version, sizeof(version));
541
542	stream->Write(&fViewMode, sizeof(uint32));
543	stream->Write(&fLastIconMode, sizeof(uint32));
544	stream->Write(&fListOrigin, sizeof(BPoint));
545	stream->Write(&fIconOrigin, sizeof(BPoint));
546	stream->Write(&fPrimarySortAttr, sizeof(uint32));
547	stream->Write(&fPrimarySortType, sizeof(uint32));
548	stream->Write(&fSecondarySortAttr, sizeof(uint32));
549	stream->Write(&fSecondarySortType, sizeof(uint32));
550	stream->Write(&fReverseSort, sizeof(bool));
551	stream->Write(&fIconSize, sizeof(uint32));
552	stream->Write(&fLastIconSize, sizeof(uint32));
553}
554
555
556void
557BViewState::_ArchiveToMessage(BMessage &message) const
558{
559	message.AddInt32(kViewStateVersionName, kViewStateArchiveVersion);
560
561	message.AddInt32(kViewStateViewModeName, static_cast<int32>(fViewMode));
562	message.AddInt32(kViewStateLastIconModeName,
563		static_cast<int32>(fLastIconMode));
564	message.AddPoint(kViewStateListOriginName, fListOrigin);
565	message.AddPoint(kViewStateIconOriginName, fIconOrigin);
566	message.AddInt32(kViewStatePrimarySortAttrName,
567		static_cast<int32>(fPrimarySortAttr));
568	message.AddInt32(kViewStatePrimarySortTypeName,
569		static_cast<int32>(fPrimarySortType));
570	message.AddInt32(kViewStateSecondarySortAttrName,
571		static_cast<int32>(fSecondarySortAttr));
572	message.AddInt32(kViewStateSecondarySortTypeName,
573		static_cast<int32>(fSecondarySortType));
574	message.AddBool(kViewStateReverseSortName, fReverseSort);
575	message.AddInt32(kViewStateIconSizeName, static_cast<int32>(fIconSize));
576	message.AddInt32(kViewStateLastIconSizeName,
577		static_cast<int32>(fLastIconSize));
578}
579