1/*****************************************************************************/
2// Expander
3// Written by J��r��me Duval
4//
5// ExpanderSettings.cpp
6//
7// Code from Diskprobe by Axel D��rfler
8//
9// Copyright (c) 2004 Haiku Project
10//
11// Permission is hereby granted, free of charge, to any person obtaining a
12// copy of this software and associated documentation files (the "Software"),
13// to deal in the Software without restriction, including without limitation
14// the rights to use, copy, modify, merge, publish, distribute, sublicense,
15// and/or sell copies of the Software, and to permit persons to whom the
16// Software is furnished to do so, subject to the following conditions:
17//
18// The above copyright notice and this permission notice shall be included
19// in all copies or substantial portions of the Software.
20//
21// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27// DEALINGS IN THE SOFTWARE.
28/*****************************************************************************/
29
30
31#include "ExpanderSettings.h"
32
33#include <ByteOrder.h>
34#include <Directory.h>
35#include <Screen.h>
36#include <FindDirectory.h>
37#include <Entry.h>
38#include <stdlib.h>
39#include <string.h>
40#include <Path.h>
41
42
43//	Format of Expander_Settings
44//	1st byte :	unknown (0x1)
45//	2nd byte :	Automatically expand files (default : 0x0)
46//	3rd byte :	Close when done (default : 0x0)
47//	4th byte :	0x66
48//				0x63 (default)
49//				0x65
50//	5th byte : 	unknown (0x0)
51//	4 bytes : 	dev_t	(default : 0xffff)
52//	8 bytes : 	ino_t	(default : 0xfffffffff)
53//	4 bytes : 	name length (big endian) (default : 0x0)
54//	n bytes : 	name	(default : "")
55//	1 byte : 	Open destination folder (default : 0x1)
56//	1 byte : 	Show content listing (default : 0x0)
57//	4 bytes : 	window position topleft x (default : 0x4842)
58//	4 bytes : 	window position topleft y (default : 0x4842)
59
60
61template<typename T> bool
62read_data(BFile& file, T& value)
63{
64	return file.Read(&value, sizeof(T)) == (ssize_t)sizeof(T);
65}
66
67
68//	#pragma mark - ExpanderSettings
69
70
71ExpanderSettings::ExpanderSettings()
72	:
73	fMessage(kMsgExpanderSettings),
74	fUpdated(false)
75{
76	fMessage.AddBool("automatically_expand_files", false);
77	fMessage.AddBool("close_when_done", true);
78	fMessage.AddInt8("destination_folder", 0x63);
79	entry_ref ref;
80	fMessage.AddRef("destination_folder_use", &ref);
81	fMessage.AddBool("open_destination_folder", true);
82	fMessage.AddBool("show_contents_listing", false);
83	fMessage.AddPoint("window_position", BPoint(50, 50));
84
85	BFile file;
86	if (Open(&file, B_READ_ONLY) != B_OK)
87		return;
88
89	// TODO: load/save settings as flattened BMessage - but not yet,
90	//       since that will break compatibility with R5's Expander
91
92	bool unknown;
93	bool automaticallyExpandFiles;
94	bool closeWhenDone;
95	int8 destinationFolder;
96	bool openDestinationFolder;
97	bool showContentsListing;
98	BPoint position;
99	char name[B_FILE_NAME_LENGTH] = {'\0'};
100	int32 nameSize;
101	if (read_data(file, unknown)
102		&& read_data(file, automaticallyExpandFiles)
103		&& read_data(file, closeWhenDone)
104		&& read_data(file, destinationFolder)
105		&& read_data(file, unknown)
106		&& read_data(file, ref.device)
107		&& read_data(file, ref.directory)
108		&& read_data(file, nameSize)
109		&& (nameSize <= 0 || file.Read(name, nameSize) == nameSize)
110		&& read_data(file, openDestinationFolder)
111		&& read_data(file, showContentsListing)
112		&& read_data(file, position)) {
113		if (nameSize > 0 && nameSize < B_FILE_NAME_LENGTH) {
114			name[nameSize] = '\0';
115			ref.set_name(name);
116		}
117
118		// check if the window position is on screen at all
119		BScreen screen;
120		if (screen.Frame().Contains(position))
121			fMessage.ReplacePoint("window_position", position);
122
123		fMessage.ReplaceBool("automatically_expand_files",
124			automaticallyExpandFiles);
125		fMessage.ReplaceBool("close_when_done", closeWhenDone);
126		if (destinationFolder == 0x66
127			|| destinationFolder == 0x63
128			|| destinationFolder == 0x65) {
129			fMessage.ReplaceInt8("destination_folder", destinationFolder);
130		}
131
132		BEntry entry(&ref);
133		if (entry.Exists())
134			fMessage.ReplaceRef("destination_folder_use", &ref);
135
136		fMessage.ReplaceBool("open_destination_folder", openDestinationFolder);
137		fMessage.ReplaceBool("show_contents_listing", showContentsListing);
138	}
139}
140
141
142ExpanderSettings::~ExpanderSettings()
143{
144	// only save the settings if something has changed
145	if (!fUpdated)
146		return;
147
148	BFile file;
149	if (Open(&file, B_CREATE_FILE | B_WRITE_ONLY) != B_OK)
150		return;
151
152	bool automaticallyExpandFiles;
153	bool closeWhenDone;
154	int8 destinationFolder;
155	entry_ref ref;
156	bool openDestinationFolder;
157	bool showContentsListing;
158	BPoint position;
159	bool unknown = 1;
160
161	if (fMessage.FindPoint("window_position", &position) == B_OK
162		&& fMessage.FindBool("automatically_expand_files",
163			&automaticallyExpandFiles) == B_OK
164		&& fMessage.FindBool("close_when_done", &closeWhenDone) == B_OK
165		&& fMessage.FindInt8("destination_folder", &destinationFolder) == B_OK
166		&& fMessage.FindRef("destination_folder_use", &ref) == B_OK
167		&& fMessage.FindBool("open_destination_folder",
168			&openDestinationFolder) == B_OK
169		&& fMessage.FindBool("show_contents_listing",
170			&showContentsListing) == B_OK) {
171		file.Write(&unknown, sizeof(unknown));
172		file.Write(&automaticallyExpandFiles, sizeof(automaticallyExpandFiles));
173		file.Write(&closeWhenDone, sizeof(closeWhenDone));
174		file.Write(&destinationFolder, sizeof(destinationFolder));
175		unknown = 0;
176		file.Write(&unknown, sizeof(unknown));
177		file.Write(&ref.device, sizeof(ref.device));
178		file.Write(&ref.directory, sizeof(ref.directory));
179		int32 nameSize = 0;
180		if (ref.name)
181			nameSize = strlen(ref.name);
182
183		file.Write(&nameSize, sizeof(nameSize));
184		file.Write(ref.name, nameSize);
185		file.Write(&openDestinationFolder, sizeof(openDestinationFolder));
186		file.Write(&showContentsListing, sizeof(showContentsListing));
187		file.Write(&position, sizeof(position));
188	}
189}
190
191
192/*static*/ status_t
193ExpanderSettings::GetSettingsDirectoryPath(BPath& _path)
194{
195	status_t error = find_directory(B_USER_SETTINGS_DIRECTORY, &_path);
196	return error == B_OK ? _path.Append("expander") : error;
197}
198
199
200status_t
201ExpanderSettings::Open(BFile* file, int32 mode)
202{
203	BPath path;
204	status_t error = GetSettingsDirectoryPath(path);
205	if (error != B_OK)
206		return error;
207
208	// create the directory, if file creation is requested
209	if ((mode & B_CREATE_FILE) != 0) {
210		error = create_directory(path.Path(), 0755);
211		if (error != B_OK)
212			return error;
213	}
214
215	error = path.Append("settings");
216	if (error != B_OK)
217		return error;
218
219	return file->SetTo(path.Path(), mode);
220}
221
222
223void
224ExpanderSettings::UpdateFrom(BMessage* message)
225{
226	bool automaticallyExpandFiles;
227	bool closeWhenDone;
228	int8 destinationFolder;
229	entry_ref ref;
230	bool openDestinationFolder;
231	bool showContentsListing;
232	BPoint position;
233
234	if (message->FindPoint("window_position", &position) == B_OK)
235		fMessage.ReplacePoint("window_position", position);
236
237	if (message->FindBool("automatically_expand_files",
238			&automaticallyExpandFiles) == B_OK) {
239		fMessage.ReplaceBool("automatically_expand_files",
240			automaticallyExpandFiles);
241	}
242
243	if (message->FindBool("close_when_done", &closeWhenDone) == B_OK)
244		fMessage.ReplaceBool("close_when_done", closeWhenDone);
245
246	if (message->FindInt8("destination_folder", &destinationFolder) == B_OK)
247		fMessage.ReplaceInt8("destination_folder", destinationFolder);
248
249	if (message->FindRef("destination_folder_use", &ref) == B_OK)
250		fMessage.ReplaceRef("destination_folder_use", &ref);
251
252	if (message->FindBool("open_destination_folder",
253			&openDestinationFolder) == B_OK)
254		fMessage.ReplaceBool("open_destination_folder", openDestinationFolder);
255
256	if (message->FindBool("show_contents_listing",
257			&showContentsListing) == B_OK) {
258		fMessage.ReplaceBool("show_contents_listing", showContentsListing);
259	}
260
261	fUpdated = true;
262}
263