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