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