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