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
81BColumn::BColumn(const char* title, float offset, float width,
82	alignment align, const char* attributeName, uint32 attrType,
83	const char* displayAs, bool statField, bool editable)
84{
85	_Init(title, offset, width, align, attributeName, attrType, displayAs,
86		statField, editable);
87}
88
89
90BColumn::BColumn(const char* title, float offset, float width,
91	alignment align, const char* attributeName, uint32 attrType,
92	bool statField, bool editable)
93{
94	_Init(title, offset, width, align, attributeName, attrType, NULL,
95		statField, editable);
96}
97
98
99BColumn::~BColumn()
100{
101}
102
103
104BColumn::BColumn(BMallocIO* stream, int32 version, bool endianSwap)
105{
106	StringFromStream(&fTitle, stream, endianSwap);
107	stream->Read(&fOffset, sizeof(float));
108	stream->Read(&fWidth, sizeof(float));
109	stream->Read(&fAlignment, sizeof(alignment));
110	StringFromStream(&fAttrName, stream, endianSwap);
111	stream->Read(&fAttrHash, sizeof(uint32));
112	stream->Read(&fAttrType, sizeof(uint32));
113	stream->Read(&fStatField, sizeof(bool));
114	stream->Read(&fEditable, sizeof(bool));
115	if (version == kColumnStateArchiveVersion)
116		StringFromStream(&fDisplayAs, stream, endianSwap);
117
118	if (endianSwap) {
119		PRINT(("endian swapping column\n"));
120		fOffset = B_SWAP_FLOAT(fOffset);
121		fWidth = B_SWAP_FLOAT(fWidth);
122		STATIC_ASSERT(sizeof(BColumn::fAlignment) == sizeof(int32));
123		fAlignment = (alignment)B_SWAP_INT32(fAlignment);
124		fAttrHash = B_SWAP_INT32(fAttrHash);
125		fAttrType = B_SWAP_INT32(fAttrType);
126	}
127}
128
129
130BColumn::BColumn(const BMessage &message, int32 index)
131{
132	message.FindString(kColumnTitleName, index, &fTitle);
133	message.FindFloat(kColumnOffsetName, index, &fOffset);
134	message.FindFloat(kColumnWidthName, index, &fWidth);
135	message.FindInt32(kColumnAlignmentName, index, (int32*)&fAlignment);
136	message.FindString(kColumnAttrName, index, &fAttrName);
137	message.FindInt32(kColumnAttrHashName, index, (int32*)&fAttrHash);
138	message.FindInt32(kColumnAttrTypeName, index, (int32*)&fAttrType);
139	message.FindString(kColumnDisplayAsName, index, &fDisplayAs);
140	message.FindBool(kColumnStatFieldName, index, &fStatField);
141	message.FindBool(kColumnEditableName, index, &fEditable);
142}
143
144
145void
146BColumn::_Init(const char* title, float offset, float width,
147	alignment align, const char* attributeName, uint32 attrType,
148	const char* displayAs, bool statField, bool editable)
149{
150	fTitle = title;
151	fAttrName = attributeName;
152	fDisplayAs = displayAs;
153	fOffset = offset;
154	fWidth = width;
155	fAlignment = align;
156	fAttrHash = AttrHashString(attributeName, attrType);
157	fAttrType = attrType;
158	fStatField = statField;
159	fEditable = editable;
160}
161
162
163BColumn*
164BColumn::InstantiateFromStream(BMallocIO* stream, bool endianSwap)
165{
166	// compare stream header in canonical form
167
168	// we can't use ValidateStream(), as we preserve backwards compatibility
169	int32 version;
170	uint32 key;
171	if (stream->Read(&key, sizeof(uint32)) <= 0
172		|| stream->Read(&version, sizeof(int32)) <=0)
173		return 0;
174
175	if (endianSwap) {
176		key = SwapUInt32(key);
177		version = SwapInt32(version);
178	}
179
180	if (key != AttrHashString("BColumn", B_OBJECT_TYPE)
181		|| version < kColumnStateMinArchiveVersion)
182		return 0;
183
184//	PRINT(("instantiating column, %s\n", endianSwap ? "endian swapping," : ""));
185	return _Sanitize(new (std::nothrow) BColumn(stream, version, endianSwap));
186}
187
188
189BColumn*
190BColumn::InstantiateFromMessage(const BMessage &message, int32 index)
191{
192	int32 version = kColumnStateArchiveVersion;
193	int32 messageVersion;
194
195	if (message.FindInt32(kColumnVersionName, index, &messageVersion) != B_OK)
196		return NULL;
197
198	if (version != messageVersion)
199		return NULL;
200
201	return _Sanitize(new (std::nothrow) BColumn(message, index));
202}
203
204
205void
206BColumn::ArchiveToStream(BMallocIO* stream) const
207{
208	// write class identifier and version info
209	uint32 key = AttrHashString("BColumn", B_OBJECT_TYPE);
210	stream->Write(&key, sizeof(uint32));
211	int32 version = kColumnStateArchiveVersion;
212	stream->Write(&version, sizeof(int32));
213
214//	PRINT(("ArchiveToStream column, key %x, version %d\n", key, version));
215
216	StringToStream(&fTitle, stream);
217	stream->Write(&fOffset, sizeof(float));
218	stream->Write(&fWidth, sizeof(float));
219	stream->Write(&fAlignment, sizeof(alignment));
220	StringToStream(&fAttrName, stream);
221	stream->Write(&fAttrHash, sizeof(uint32));
222	stream->Write(&fAttrType, sizeof(uint32));
223	stream->Write(&fStatField, sizeof(bool));
224	stream->Write(&fEditable, sizeof(bool));
225	StringToStream(&fDisplayAs, stream);
226}
227
228
229void
230BColumn::ArchiveToMessage(BMessage &message) const
231{
232	message.AddInt32(kColumnVersionName, kColumnStateArchiveVersion);
233
234	message.AddString(kColumnTitleName, fTitle);
235	message.AddFloat(kColumnOffsetName, fOffset);
236	message.AddFloat(kColumnWidthName, fWidth);
237	message.AddInt32(kColumnAlignmentName, fAlignment);
238	message.AddString(kColumnAttrName, fAttrName);
239	message.AddInt32(kColumnAttrHashName, static_cast<int32>(fAttrHash));
240	message.AddInt32(kColumnAttrTypeName, static_cast<int32>(fAttrType));
241	message.AddString(kColumnDisplayAsName, fDisplayAs.String());
242	message.AddBool(kColumnStatFieldName, fStatField);
243	message.AddBool(kColumnEditableName, fEditable);
244}
245
246
247BColumn *
248BColumn::_Sanitize(BColumn* column)
249{
250	if (column == NULL)
251		return NULL;
252
253	// sanity-check the resulting column
254	if (column->fTitle.Length() > 500
255		|| column->fOffset < 0
256		|| column->fOffset > 10000
257		|| column->fWidth < 0
258		|| column->fWidth > 10000
259		|| (int32)column->fAlignment < B_ALIGN_LEFT
260		|| (int32)column->fAlignment > B_ALIGN_CENTER
261		|| column->fAttrName.Length() > 500) {
262		PRINT(("column data not valid\n"));
263		delete column;
264		return NULL;
265	}
266#if DEBUG
267// TODO: Whatever this is supposed to mean, fix it.
268//	else if (endianSwap)
269//		PRINT(("Instantiated foreign column ok\n"));
270#endif
271
272	return column;
273}
274
275
276//	#pragma mark -
277
278
279BViewState::BViewState()
280{
281	_Init();
282	_StorePreviousState();
283}
284
285
286BViewState::BViewState(BMallocIO* stream, bool endianSwap)
287{
288	_Init();
289	stream->Read(&fViewMode, sizeof(uint32));
290	stream->Read(&fLastIconMode, sizeof(uint32));
291	stream->Read(&fListOrigin, sizeof(BPoint));
292	stream->Read(&fIconOrigin, sizeof(BPoint));
293	stream->Read(&fPrimarySortAttr, sizeof(uint32));
294	stream->Read(&fPrimarySortType, sizeof(uint32));
295	stream->Read(&fSecondarySortAttr, sizeof(uint32));
296	stream->Read(&fSecondarySortType, sizeof(uint32));
297	stream->Read(&fReverseSort, sizeof(bool));
298	stream->Read(&fIconSize, sizeof(uint32));
299	stream->Read(&fLastIconSize, sizeof(uint32));
300
301	if (endianSwap) {
302		PRINT(("endian swapping view state\n"));
303		fViewMode = B_SWAP_INT32(fViewMode);
304		fLastIconMode = B_SWAP_INT32(fLastIconMode);
305		fIconSize = B_SWAP_INT32(fIconSize);
306		fLastIconSize = B_SWAP_INT32(fLastIconSize);
307		swap_data(B_POINT_TYPE, &fListOrigin,
308			sizeof(fListOrigin), B_SWAP_ALWAYS);
309		swap_data(B_POINT_TYPE, &fIconOrigin,
310			sizeof(fIconOrigin), B_SWAP_ALWAYS);
311		fPrimarySortAttr = B_SWAP_INT32(fPrimarySortAttr);
312		fSecondarySortAttr = B_SWAP_INT32(fSecondarySortAttr);
313		fPrimarySortType = B_SWAP_INT32(fPrimarySortType);
314		fSecondarySortType = B_SWAP_INT32(fSecondarySortType);
315	}
316
317	_StorePreviousState();
318	_Sanitize(this, true);
319}
320
321
322BViewState::BViewState(const BMessage &message)
323{
324	_Init();
325	message.FindInt32(kViewStateViewModeName, (int32*)&fViewMode);
326	message.FindInt32(kViewStateLastIconModeName, (int32*)&fLastIconMode);
327	message.FindInt32(kViewStateLastIconSizeName,(int32*)&fLastIconSize);
328	message.FindInt32(kViewStateIconSizeName, (int32*)&fIconSize);
329	message.FindPoint(kViewStateListOriginName, &fListOrigin);
330	message.FindPoint(kViewStateIconOriginName, &fIconOrigin);
331	message.FindInt32(kViewStatePrimarySortAttrName,
332		(int32*)&fPrimarySortAttr);
333	message.FindInt32(kViewStatePrimarySortTypeName,
334		(int32*)&fPrimarySortType);
335	message.FindInt32(kViewStateSecondarySortAttrName,
336		(int32*)&fSecondarySortAttr);
337	message.FindInt32(kViewStateSecondarySortTypeName,
338		(int32*)&fSecondarySortType);
339	message.FindBool(kViewStateReverseSortName, &fReverseSort);
340
341	_StorePreviousState();
342	_Sanitize(this, true);
343}
344
345
346void
347BViewState::ArchiveToStream(BMallocIO* stream) const
348{
349	// write class identifier and verison info
350	uint32 key = AttrHashString("BViewState", B_OBJECT_TYPE);
351	stream->Write(&key, sizeof(key));
352	int32 version = kViewStateArchiveVersion;
353	stream->Write(&version, sizeof(version));
354
355	stream->Write(&fViewMode, sizeof(uint32));
356	stream->Write(&fLastIconMode, sizeof(uint32));
357	stream->Write(&fListOrigin, sizeof(BPoint));
358	stream->Write(&fIconOrigin, sizeof(BPoint));
359	stream->Write(&fPrimarySortAttr, sizeof(uint32));
360	stream->Write(&fPrimarySortType, sizeof(uint32));
361	stream->Write(&fSecondarySortAttr, sizeof(uint32));
362	stream->Write(&fSecondarySortType, sizeof(uint32));
363	stream->Write(&fReverseSort, sizeof(bool));
364	stream->Write(&fIconSize, sizeof(uint32));
365	stream->Write(&fLastIconSize, sizeof(uint32));
366}
367
368
369void
370BViewState::ArchiveToMessage(BMessage &message) const
371{
372	message.AddInt32(kViewStateVersionName, kViewStateArchiveVersion);
373
374	message.AddInt32(kViewStateViewModeName, static_cast<int32>(fViewMode));
375	message.AddInt32(kViewStateLastIconModeName,
376		static_cast<int32>(fLastIconMode));
377	message.AddPoint(kViewStateListOriginName, fListOrigin);
378	message.AddPoint(kViewStateIconOriginName, fIconOrigin);
379	message.AddInt32(kViewStatePrimarySortAttrName,
380		static_cast<int32>(fPrimarySortAttr));
381	message.AddInt32(kViewStatePrimarySortTypeName,
382		static_cast<int32>(fPrimarySortType));
383	message.AddInt32(kViewStateSecondarySortAttrName,
384		static_cast<int32>(fSecondarySortAttr));
385	message.AddInt32(kViewStateSecondarySortTypeName,
386		static_cast<int32>(fSecondarySortType));
387	message.AddBool(kViewStateReverseSortName, fReverseSort);
388	message.AddInt32(kViewStateIconSizeName, static_cast<int32>(fIconSize));
389	message.AddInt32(kViewStateLastIconSizeName,
390		static_cast<int32>(fLastIconSize));
391}
392
393
394BViewState*
395BViewState::InstantiateFromStream(BMallocIO* stream, bool endianSwap)
396{
397	// compare stream header in canonical form
398	uint32 key = AttrHashString("BViewState", B_OBJECT_TYPE);
399	int32 version = kViewStateArchiveVersion;
400
401	if (endianSwap) {
402		key = SwapUInt32(key);
403		version = SwapInt32(version);
404	}
405
406	if (!ValidateStream(stream, key, version))
407		return NULL;
408
409	return _Sanitize(new (std::nothrow) BViewState(stream, endianSwap));
410}
411
412
413BViewState*
414BViewState::InstantiateFromMessage(const BMessage &message)
415{
416	int32 version = kViewStateArchiveVersion;
417
418	int32 messageVersion;
419	if (message.FindInt32(kViewStateVersionName, &messageVersion) != B_OK)
420		return NULL;
421
422	if (version != messageVersion)
423		return NULL;
424
425	return _Sanitize(new (std::nothrow) BViewState(message));
426}
427
428
429void
430BViewState::_Init()
431{
432	fViewMode = kListMode;
433	fLastIconMode = 0;
434	fIconSize = 32;
435	fLastIconSize = 32;
436	fListOrigin.Set(0, 0);
437	fIconOrigin.Set(0, 0);
438	fPrimarySortAttr = AttrHashString(kAttrStatName, B_STRING_TYPE);
439	fPrimarySortType = B_STRING_TYPE;
440	fSecondarySortAttr = 0;
441	fSecondarySortType = 0;
442	fReverseSort = false;
443}
444
445
446void
447BViewState::_StorePreviousState()
448{
449	fPreviousViewMode = fViewMode;
450	fPreviousLastIconMode = fLastIconMode;
451	fPreviousIconSize = fIconSize;
452	fPreviousLastIconSize = fLastIconSize;
453	fPreviousListOrigin = fListOrigin;
454	fPreviousIconOrigin = fIconOrigin;
455	fPreviousPrimarySortAttr = fPrimarySortAttr;
456	fPreviousSecondarySortAttr = fSecondarySortAttr;
457	fPreviousPrimarySortType = fPrimarySortType;
458	fPreviousSecondarySortType = fSecondarySortType;
459	fPreviousReverseSort = fReverseSort;
460}
461
462
463BViewState*
464BViewState::_Sanitize(BViewState* state, bool fixOnly)
465{
466	if (state == NULL)
467		return NULL;
468
469	if (state->fViewMode == kListMode) {
470		if (state->fListOrigin.x < 0)
471			state->fListOrigin.x = 0;
472		if (state->fListOrigin.y < 0)
473			state->fListOrigin.y = 0;
474	}
475	if (state->fIconSize < 16)
476		state->fIconSize = 16;
477	if (state->fIconSize > 128)
478		state->fIconSize = 128;
479	if (state->fLastIconSize < 16)
480		state->fLastIconSize = 16;
481	if (state->fLastIconSize > 128)
482		state->fLastIconSize = 128;
483
484	if (fixOnly)
485		return state;
486
487	// do a sanity check here
488	if ((state->fViewMode != kListMode
489			&& state->fViewMode != kIconMode
490			&& state->fViewMode != kMiniIconMode
491			&& state->fViewMode != 0)
492		|| (state->fLastIconMode != kListMode
493			&& state->fLastIconMode != kIconMode
494			&& state->fLastIconMode != kMiniIconMode
495			&& state->fLastIconMode != 0)) {
496		PRINT(("Bad data instantiating ViewState, view mode %" B_PRIx32
497			", lastIconMode %" B_PRIx32 "\n", state->fViewMode,
498			state->fLastIconMode));
499
500		delete state;
501		return NULL;
502	}
503#if DEBUG
504// TODO: Whatever this is supposed to mean, fix it.
505//	else if (endianSwap)
506//		PRINT(("Instantiated foreign view state ok\n"));
507#endif
508
509	return state;
510}
511