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