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