1 /* 2 * Copyright 2003-2013, Haiku, Inc. All Rights Reserved. 3 * Copyright (c) 2004 Daniel Furrer <assimil8or@users.sourceforge.net> 4 * Copyright (c) 2003-4 Kian Duffy <myob@users.sourceforge.net> 5 * Copyright (c) 1998,99 Kazuho Okui and Takashi Murai. 6 * 7 * Distributed unter the terms of the MIT License. 8 * 9 * Authors: 10 * Kian Duffy, myob@users.sourceforge.net 11 * Daniel Furrer, assimil8or@users.sourceforge.net 12 * Siarzhuk Zharski, zharik@gmx.li 13 */ 14 15 16 #include "PrefHandler.h" 17 18 #include <stdio.h> 19 #include <stdlib.h> 20 #include <string.h> 21 #include <unistd.h> 22 23 #include <Catalog.h> 24 #include <Directory.h> 25 #include <Entry.h> 26 #include <File.h> 27 #include <FindDirectory.h> 28 #include <Font.h> 29 #include <GraphicsDefs.h> 30 #include <Locale.h> 31 #include <Message.h> 32 #include <NodeInfo.h> 33 #include <Path.h> 34 35 #include "TermConst.h" 36 37 38 /* 39 * Startup preference settings. 40 */ 41 static const pref_defaults kTermDefaults[] = { 42 { PREF_COLS, "80" }, 43 { PREF_ROWS, "25" }, 44 45 // No need for PREF_HALF_FONT_FAMILY/_STYLE defaults here, 46 // these entries will be filled with corresponding params 47 // of the current system fixed font if they are not 48 // available in the settings file 49 50 { PREF_HALF_FONT_SIZE, "12" }, 51 52 { PREF_TEXT_FORE_COLOR, " 0, 0, 0" }, 53 { PREF_TEXT_BACK_COLOR, "255, 255, 255" }, 54 { PREF_CURSOR_FORE_COLOR, "255, 255, 255" }, 55 { PREF_CURSOR_BACK_COLOR, " 0, 0, 0" }, 56 { PREF_SELECT_FORE_COLOR, "255, 255, 255" }, 57 { PREF_SELECT_BACK_COLOR, " 0, 0, 0" }, 58 59 { PREF_IM_FORE_COLOR, " 0, 0, 0" }, 60 { PREF_IM_BACK_COLOR, "152, 203, 255" }, 61 { PREF_IM_SELECT_COLOR, "255, 152, 152" }, 62 63 { PREF_ANSI_BLACK_COLOR, " 40, 40, 40" }, 64 { PREF_ANSI_RED_COLOR, "204, 0, 0" }, 65 { PREF_ANSI_GREEN_COLOR, " 78, 154, 6" }, 66 { PREF_ANSI_YELLOW_COLOR, "218, 168, 0" }, 67 { PREF_ANSI_BLUE_COLOR, " 51, 102, 152" }, 68 { PREF_ANSI_MAGENTA_COLOR, "115, 68, 123" }, 69 { PREF_ANSI_CYAN_COLOR, " 6, 152, 154" }, 70 { PREF_ANSI_WHITE_COLOR, "245, 245, 245" }, 71 72 { PREF_ANSI_BLACK_HCOLOR, "128, 128, 128" }, 73 { PREF_ANSI_RED_HCOLOR, "255, 0, 0" }, 74 { PREF_ANSI_GREEN_HCOLOR, " 0, 255, 0" }, 75 { PREF_ANSI_YELLOW_HCOLOR, "255, 255, 0" }, 76 { PREF_ANSI_BLUE_HCOLOR, " 0, 0, 255" }, 77 { PREF_ANSI_MAGENTA_HCOLOR, "255, 0, 255" }, 78 { PREF_ANSI_CYAN_HCOLOR, " 0, 255, 255" }, 79 { PREF_ANSI_WHITE_HCOLOR, "255, 255, 255" }, 80 81 { PREF_HISTORY_SIZE, "10000" }, 82 83 { PREF_TEXT_ENCODING, "UTF-8" }, 84 85 { PREF_IM_AWARE, "0"}, 86 87 { PREF_TAB_TITLE, "%1d: %p" }, 88 { PREF_WINDOW_TITLE, "%T %i: %t" }, 89 { PREF_BLINK_CURSOR, PREF_TRUE }, 90 { PREF_WARN_ON_EXIT, PREF_TRUE }, 91 { PREF_CURSOR_STYLE, PREF_BLOCK_CURSOR }, 92 { PREF_EMULATE_BOLD, PREF_FALSE }, 93 94 { NULL, NULL}, 95 }; 96 97 98 PrefHandler *PrefHandler::sPrefHandler = NULL; 99 100 101 PrefHandler::PrefHandler() 102 : 103 fContainer('Pref') 104 { 105 _LoadFromDefault(kTermDefaults); 106 107 BPath path; 108 GetDefaultPath(path); 109 OpenText(path.Path()); 110 111 _ConfirmFont(be_fixed_font); 112 } 113 114 115 PrefHandler::PrefHandler(const PrefHandler* p) 116 { 117 fContainer = p->fContainer; 118 } 119 120 121 PrefHandler::~PrefHandler() 122 { 123 } 124 125 126 /* static */ 127 PrefHandler * 128 PrefHandler::Default() 129 { 130 if (sPrefHandler == NULL) 131 sPrefHandler = new PrefHandler(); 132 return sPrefHandler; 133 } 134 135 136 /* static */ 137 void 138 PrefHandler::DeleteDefault() 139 { 140 delete sPrefHandler; 141 sPrefHandler = NULL; 142 } 143 144 145 /* static */ 146 void 147 PrefHandler::SetDefault(PrefHandler *prefHandler) 148 { 149 DeleteDefault(); 150 sPrefHandler = prefHandler; 151 } 152 153 154 /* static */ 155 status_t 156 PrefHandler::GetDefaultPath(BPath& path) 157 { 158 status_t status; 159 status = find_directory(B_USER_SETTINGS_DIRECTORY, &path, true); 160 if (status != B_OK) 161 return status; 162 163 status = path.Append("Terminal"); 164 if (status != B_OK) 165 return status; 166 167 // Just create the directory. Harmless if already there 168 status = create_directory(path.Path(), 0755); 169 if (status != B_OK) 170 return status; 171 172 return path.Append("Default"); 173 } 174 175 176 status_t 177 PrefHandler::OpenText(const char *path) 178 { 179 return _LoadFromTextFile(path); 180 } 181 182 183 void 184 PrefHandler::SaveDefaultAsText() 185 { 186 BPath path; 187 if (GetDefaultPath(path) == B_OK) 188 SaveAsText(path.Path(), PREFFILE_MIMETYPE); 189 } 190 191 192 void 193 PrefHandler::SaveAsText(const char *path, const char *mimetype, 194 const char *signature) 195 { 196 // make sure the target path exists 197 #if 0 198 BPath directoryPath(path); 199 if (directoryPath.GetParent(&directoryPath) == B_OK) 200 create_directory(directoryPath.Path(), 0755); 201 #endif 202 203 BFile file(path, B_WRITE_ONLY | B_CREATE_FILE | B_ERASE_FILE); 204 char buffer[512]; 205 type_code type; 206 const char *key; 207 208 for (int32 i = 0; 209 #ifdef B_BEOS_VERSION_DANO 210 fContainer.GetInfo(B_STRING_TYPE, i, &key, &type) == B_OK; 211 #else 212 fContainer.GetInfo(B_STRING_TYPE, i, (char**)&key, &type) == B_OK; 213 #endif 214 i++) { 215 int len = snprintf(buffer, sizeof(buffer), "\"%s\" , \"%s\"\n", 216 key, getString(key)); 217 file.Write(buffer, len); 218 } 219 220 if (mimetype != NULL) { 221 BNodeInfo info(&file); 222 info.SetType(mimetype); 223 info.SetPreferredApp(signature); 224 } 225 } 226 227 228 int32 229 PrefHandler::getInt32(const char *key) 230 { 231 const char *value = fContainer.FindString(key); 232 if (value == NULL) 233 return 0; 234 235 return atoi(value); 236 } 237 238 239 float 240 PrefHandler::getFloat(const char *key) 241 { 242 const char *value = fContainer.FindString(key); 243 if (value == NULL) 244 return 0; 245 246 return atof(value); 247 } 248 249 250 #undef B_TRANSLATION_CONTEXT 251 #define B_TRANSLATION_CONTEXT "Terminal getString" 252 253 const char* 254 PrefHandler::getString(const char *key) 255 { 256 const char *buffer; 257 if (fContainer.FindString(key, &buffer) != B_OK) 258 buffer = B_TRANSLATE("Error!"); 259 260 //printf("%x GET %s: %s\n", this, key, buf); 261 return buffer; 262 } 263 264 265 bool 266 PrefHandler::getBool(const char *key) 267 { 268 const char *value = fContainer.FindString(key); 269 if (value == NULL) 270 return false; 271 272 return strcmp(value, PREF_TRUE) == 0; 273 } 274 275 276 int 277 PrefHandler::getCursor(const char *key) 278 { 279 const char *value = fContainer.FindString(key); 280 if (value != NULL && strcmp(value, PREF_BLOCK_CURSOR) != 0) { 281 if (strcmp(value, PREF_UNDERLINE_CURSOR) == 0) 282 return UNDERLINE_CURSOR; 283 if (strcmp(value, PREF_IBEAM_CURSOR) == 0) 284 return IBEAM_CURSOR; 285 } 286 return BLOCK_CURSOR; 287 } 288 289 290 #undef B_TRANSLATION_CONTEXT 291 #define B_TRANSLATION_CONTEXT "Terminal getRGB" 292 293 /** Returns RGB data from given key. */ 294 295 rgb_color 296 PrefHandler::getRGB(const char *key) 297 { 298 rgb_color col; 299 int r, g, b; 300 301 if (const char *s = fContainer.FindString(key)) { 302 sscanf(s, "%d, %d, %d", &r, &g, &b); 303 } else { 304 fprintf(stderr, 305 "PrefHandler::getRGB(%s) - key not found\n", key); 306 r = g = b = 0; 307 } 308 309 col.red = r; 310 col.green = g; 311 col.blue = b; 312 col.alpha = 255; 313 return col; 314 } 315 316 317 /** Setting Int32 data with key. */ 318 319 void 320 PrefHandler::setInt32(const char *key, int32 data) 321 { 322 char buffer[32]; 323 snprintf(buffer, sizeof(buffer), "%d", (int)data); 324 setString(key, buffer); 325 } 326 327 328 /** Setting Float data with key */ 329 330 void 331 PrefHandler::setFloat(const char *key, float data) 332 { 333 char buffer[32]; 334 snprintf(buffer, sizeof(buffer), "%g", data); 335 setString(key, buffer); 336 } 337 338 339 /** Setting Bool data with key */ 340 341 void 342 PrefHandler::setBool(const char *key, bool data) 343 { 344 if (data) 345 setString(key, PREF_TRUE); 346 else 347 setString(key, PREF_FALSE); 348 } 349 350 351 /** Setting CString data with key */ 352 353 void 354 PrefHandler::setString(const char *key, const char *data) 355 { 356 //printf("%x SET %s: %s\n", this, key, data); 357 fContainer.RemoveName(key); 358 fContainer.AddString(key, data); 359 } 360 361 362 /** Setting RGB data with key */ 363 364 void 365 PrefHandler::setRGB(const char *key, const rgb_color data) 366 { 367 char buffer[32]; 368 snprintf(buffer, sizeof(buffer), "%d, %d, %d", data.red, data.green, data.blue); 369 setString(key, buffer); 370 } 371 372 373 /** Check any peference stored or not. */ 374 375 bool 376 PrefHandler::IsEmpty() const 377 { 378 return fContainer.IsEmpty(); 379 } 380 381 382 void 383 PrefHandler::_ConfirmFont(const BFont *fallbackFont) 384 { 385 font_family family; 386 font_style style; 387 388 const char *prefFamily = getString(PREF_HALF_FONT_FAMILY); 389 int32 familiesCount = (prefFamily != NULL) ? count_font_families() : 0; 390 391 for (int32 i = 0; i < familiesCount; i++) { 392 if (get_font_family(i, &family) != B_OK 393 || strcmp(family, prefFamily) != 0) 394 continue; 395 396 const char *prefStyle = getString(PREF_HALF_FONT_STYLE); 397 int32 stylesCount = (prefStyle != NULL) ? count_font_styles(family) : 0; 398 399 for (int32 j = 0; j < stylesCount; j++) { 400 // check style if we can safely use this font 401 if (get_font_style(family, j, &style) == B_OK 402 && strcmp(style, prefStyle) == 0) 403 return; 404 } 405 } 406 407 // use fall-back font 408 fallbackFont->GetFamilyAndStyle(&family, &style); 409 setString(PREF_HALF_FONT_FAMILY, family); 410 setString(PREF_HALF_FONT_STYLE, style); 411 } 412 413 414 status_t 415 PrefHandler::_LoadFromDefault(const pref_defaults* defaults) 416 { 417 if (defaults == NULL) 418 return B_ERROR; 419 420 while (defaults->key) { 421 setString(defaults->key, defaults->item); 422 ++defaults; 423 } 424 425 return B_OK; 426 } 427 428 429 /** Text is "key","Content" 430 * Comment : Start with '#' 431 */ 432 433 status_t 434 PrefHandler::_LoadFromTextFile(const char * path) 435 { 436 char buffer[1024]; 437 char key[B_FIELD_NAME_LENGTH], data[512]; 438 int n; 439 FILE *file; 440 441 file = fopen(path, "r"); 442 if (file == NULL) 443 return B_ENTRY_NOT_FOUND; 444 445 while (fgets(buffer, sizeof(buffer), file) != NULL) { 446 if (*buffer == '#') 447 continue; 448 449 n = sscanf(buffer, "%*[\"]%[^\"]%*[\"]%*[^\"]%*[\"]%[^\"]", key, data); 450 if (n == 2) 451 setString(key, data); 452 } 453 454 fclose(file); 455 return B_OK; 456 } 457