xref: /haiku/src/apps/text_search/Model.cpp (revision a5a3b2d9a3d95cbae71eaf371708c73a1780ac0d)
1 /*
2  * Copyright (c) 1998-2007 Matthijs Hollemans
3  * Distributed under the terms of the MIT License.
4  */
5 
6 
7 #include "Model.h"
8 
9 #include <new>
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 
14 #include <Directory.h>
15 #include <Entry.h>
16 #include <File.h>
17 #include <FindDirectory.h>
18 #include <List.h>
19 #include <MenuItem.h>
20 #include <Path.h>
21 #include <Roster.h>
22 
23 #include "GlobalDefs.h"
24 
25 
26 using std::nothrow;
27 
28 
29 Model::Model()
30 	:
31 	fDirectory(),
32 	fSelectedFiles((uint32)0),
33 
34 	fRecurseDirs(true),
35 	fRecurseLinks(false),
36 	fSkipDotDirs(true),
37 	fCaseSensitive(false),
38 	fEscapeText(true),
39 	fTextOnly(true),
40 	fInvokePe(false),
41 
42 	fFrame(100, 100, 500, 400),
43 
44 	fState(STATE_IDLE),
45 
46 	fFilePanelPath(""),
47 
48 	fEncoding(0)
49 {
50 	BPath path;
51 	if (find_directory(B_USER_DIRECTORY, &path) == B_OK)
52 		fFilePanelPath = path.Path();
53 	else
54 		fFilePanelPath = "/boot/home";
55 
56 	entry_ref dummy;
57 	if (be_roster->FindApp(PE_SIGNATURE, &dummy) == B_OK) {
58 		// Pe is installed, change the default settings
59 		fInvokePe = true;
60 	}
61 }
62 
63 
64 status_t
65 Model::LoadPrefs()
66 {
67 	BFile file;
68 	status_t status = _OpenFile(&file, PREFS_FILE);
69 	if (status != B_OK)
70 		return status;
71 
72 	status = file.Lock();
73 	if (status != B_OK)
74 		return status;
75 
76 	int32 value;
77 
78 	if (file.ReadAttr("RecurseDirs", B_INT32_TYPE, 0, &value,
79 			sizeof(int32)) > 0)
80 		fRecurseDirs = (value != 0);
81 
82 	if (file.ReadAttr("RecurseLinks", B_INT32_TYPE, 0, &value,
83 			sizeof(int32)) > 0)
84 		fRecurseLinks = (value != 0);
85 
86 	if (file.ReadAttr("SkipDotDirs", B_INT32_TYPE, 0, &value,
87 			sizeof(int32)) > 0)
88 		fSkipDotDirs = (value != 0);
89 
90 	if (file.ReadAttr("CaseSensitive", B_INT32_TYPE, 0, &value,
91 			sizeof(int32)) > 0)
92 		fCaseSensitive = (value != 0);
93 
94 	if (file.ReadAttr("EscapeText", B_INT32_TYPE, 0, &value, sizeof(int32)) > 0)
95 		fEscapeText = (value != 0);
96 
97 	if (file.ReadAttr("TextOnly", B_INT32_TYPE, 0, &value, sizeof(int32)) > 0)
98 		fTextOnly = (value != 0);
99 
100 	if (file.ReadAttr("InvokePe", B_INT32_TYPE, 0, &value, sizeof(int32)) > 0)
101 		fInvokePe = (value != 0);
102 
103 	char buffer [B_PATH_NAME_LENGTH+1];
104 	int32 length = file.ReadAttr("FilePanelPath", B_STRING_TYPE, 0, &buffer,
105 		sizeof(buffer));
106 	if (length > 0) {
107 		buffer[length] = '\0';
108 		fFilePanelPath = buffer;
109 	}
110 
111 	file.ReadAttr("WindowFrame", B_RECT_TYPE, 0, &fFrame, sizeof(BRect));
112 
113 	if (file.ReadAttr("Encoding", B_INT32_TYPE, 0, &value, sizeof(int32)) > 0)
114 		fEncoding = value;
115 
116 	file.Unlock();
117 
118 	return B_OK;
119 }
120 
121 
122 status_t
123 Model::SavePrefs()
124 {
125 	BFile file;
126 	status_t status = _OpenFile(&file, PREFS_FILE,
127 		B_CREATE_FILE | B_WRITE_ONLY);
128 	if (status != B_OK)
129 		return status;
130 
131 	status = file.Lock();
132 	if (status != B_OK)
133 		return status;
134 
135 	int32 value = 2;
136 	file.WriteAttr("Version", B_INT32_TYPE, 0, &value, sizeof(int32));
137 
138 	value = fRecurseDirs ? 1 : 0;
139 	file.WriteAttr("RecurseDirs", B_INT32_TYPE, 0, &value, sizeof(int32));
140 
141 	value = fRecurseLinks ? 1 : 0;
142 	file.WriteAttr("RecurseLinks", B_INT32_TYPE, 0, &value, sizeof(int32));
143 
144 	value = fSkipDotDirs ? 1 : 0;
145 	file.WriteAttr("SkipDotDirs", B_INT32_TYPE, 0, &value, sizeof(int32));
146 
147 	value = fCaseSensitive ? 1 : 0;
148 	file.WriteAttr("CaseSensitive", B_INT32_TYPE, 0, &value, sizeof(int32));
149 
150 	value = fEscapeText ? 1 : 0;
151 	file.WriteAttr("EscapeText", B_INT32_TYPE, 0, &value, sizeof(int32));
152 
153 	value = fTextOnly ? 1 : 0;
154 	file.WriteAttr("TextOnly", B_INT32_TYPE, 0, &value, sizeof(int32));
155 
156 	value = fInvokePe ? 1 : 0;
157 	file.WriteAttr("InvokePe", B_INT32_TYPE, 0, &value, sizeof(int32));
158 
159 	file.WriteAttr("WindowFrame", B_RECT_TYPE, 0, &fFrame, sizeof(BRect));
160 
161 	file.WriteAttr("FilePanelPath", B_STRING_TYPE, 0, fFilePanelPath.String(),
162 		fFilePanelPath.Length() + 1);
163 
164 	file.WriteAttr("Encoding", B_INT32_TYPE, 0, &fEncoding, sizeof(int32));
165 
166 	file.Sync();
167 	file.Unlock();
168 
169 	return B_OK;
170 }
171 
172 
173 void
174 Model::AddToHistory(const char* text)
175 {
176 	BList items;
177 	_LoadHistory(items);
178 
179 	BString* string = new (nothrow) BString(text);
180 	if (string == NULL || !items.AddItem(string)) {
181 		delete string;
182 		_FreeHistory(items);
183 		return;
184 	}
185 
186 	int32 count = items.CountItems() - 1;
187 		// don't check last item, since that's the one we just added
188 	for (int32 t = 0; t < count; ++t) {
189 		// If the same text is already in the list,
190 		// then remove it first. Case-sensitive.
191 		BString* string = static_cast<BString*>(items.ItemAt(t));
192 		if (*string == text) {
193 			delete static_cast<BString*>(items.RemoveItem(t));
194 			break;
195 		}
196 	}
197 
198 	while (items.CountItems() >= HISTORY_LIMIT)
199 		delete static_cast<BString*>(items.RemoveItem((int32)0));
200 
201 	_SaveHistory(items);
202 	_FreeHistory(items);
203 }
204 
205 
206 void
207 Model::FillHistoryMenu(BMenu* menu) const
208 {
209 	BList items;
210 	if (!_LoadHistory(items))
211 		return;
212 
213 	for (int32 t = items.CountItems() - 1; t >= 0; --t) {
214 		BString* item = static_cast<BString*>(items.ItemAtFast(t));
215 		BMessage* message = new BMessage(MSG_SELECT_HISTORY);
216 		message->AddString("text", item->String());
217 		menu->AddItem(new BMenuItem(item->String(), message));
218 	}
219 
220 	_FreeHistory(items);
221 }
222 
223 
224 // #pragma mark - private
225 
226 
227 bool
228 Model::_LoadHistory(BList& items) const
229 {
230 	BFile file;
231 	status_t status = _OpenFile(&file, PREFS_FILE);
232 	if (status != B_OK)
233 		return false;
234 
235 	status = file.Lock();
236 	if (status != B_OK)
237 		return false;
238 
239 	BMessage message;
240 	status = message.Unflatten(&file);
241 	if (status != B_OK)
242 		return false;
243 
244 	file.Unlock();
245 
246 	BString string;
247 	for (int32 x = 0; message.FindString("string", x, &string) == B_OK; x++) {
248 		BString* copy = new (nothrow) BString(string);
249 		if (copy == NULL || !items.AddItem(copy)) {
250 			delete copy;
251 			break;
252 		}
253 	}
254 
255 	return true;
256 }
257 
258 
259 status_t
260 Model::_SaveHistory(const BList& items) const
261 {
262 	BFile file;
263 	status_t status = _OpenFile(&file, PREFS_FILE,
264 		B_CREATE_FILE | B_WRITE_ONLY | B_ERASE_FILE,
265 		B_USER_SETTINGS_DIRECTORY, NULL);
266 	if (status != B_OK)
267 		return status;
268 
269 	status = file.Lock();
270 	if (status != B_OK)
271 		return status;
272 
273 	BMessage message;
274 	int32 count = items.CountItems();
275 	for (int32 i = 0; i < count; i++) {
276 		BString* string = static_cast<BString*>(items.ItemAtFast(i));
277 
278 		if (message.AddString("string", string->String()) != B_OK)
279 			break;
280 	}
281 
282 	status = message.Flatten(&file);
283 	file.SetSize(message.FlattenedSize());
284 	file.Sync();
285 	file.Unlock();
286 
287 	return status;
288 }
289 
290 
291 void
292 Model::_FreeHistory(const BList& items) const
293 {
294 	for (int32 t = items.CountItems() - 1; t >= 0; --t)
295 		delete static_cast<BString*>((items.ItemAtFast(t)));
296 }
297 
298 
299 status_t
300 Model::_OpenFile(BFile* file, const char* name, uint32 openMode,
301 	directory_which which, BVolume* volume) const
302 {
303 	if (file == NULL)
304 		return B_BAD_VALUE;
305 
306 	BPath path;
307 	status_t status = find_directory(which, &path, true, volume);
308 	if (status != B_OK)
309 		return status;
310 
311 	status = path.Append(PREFS_FILE);
312 	if (status != B_OK)
313 		return status;
314 
315 	status = file->SetTo(path.Path(), openMode);
316 	if (status != B_OK)
317 		return status;
318 
319 	status = file->InitCheck();
320 	if (status != B_OK)
321 		return status;
322 
323 	return B_OK;
324 }
325