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(bool loadSettings) 102 : 103 fContainer('Pref') 104 { 105 _LoadFromDefault(kTermDefaults); 106 107 if (loadSettings) { 108 BPath path; 109 GetDefaultPath(path); 110 OpenText(path.Path()); 111 } 112 113 _ConfirmFont(be_fixed_font); 114 } 115 116 117 PrefHandler::PrefHandler(const PrefHandler* p) 118 { 119 fContainer = p->fContainer; 120 } 121 122 123 PrefHandler::~PrefHandler() 124 { 125 } 126 127 128 /* static */ 129 PrefHandler * 130 PrefHandler::Default() 131 { 132 if (sPrefHandler == NULL) 133 sPrefHandler = new PrefHandler(); 134 return sPrefHandler; 135 } 136 137 138 /* static */ 139 void 140 PrefHandler::DeleteDefault() 141 { 142 delete sPrefHandler; 143 sPrefHandler = NULL; 144 } 145 146 147 /* static */ 148 void 149 PrefHandler::SetDefault(PrefHandler *prefHandler) 150 { 151 DeleteDefault(); 152 sPrefHandler = prefHandler; 153 } 154 155 156 /* static */ 157 status_t 158 PrefHandler::GetDefaultPath(BPath& path) 159 { 160 status_t status; 161 status = find_directory(B_USER_SETTINGS_DIRECTORY, &path, true); 162 if (status != B_OK) 163 return status; 164 165 status = path.Append("Terminal"); 166 if (status != B_OK) 167 return status; 168 169 // Just create the directory. Harmless if already there 170 status = create_directory(path.Path(), 0755); 171 if (status != B_OK) 172 return status; 173 174 return path.Append("Default"); 175 } 176 177 178 status_t 179 PrefHandler::OpenText(const char *path) 180 { 181 return _LoadFromTextFile(path); 182 } 183 184 185 void 186 PrefHandler::SaveDefaultAsText() 187 { 188 BPath path; 189 if (GetDefaultPath(path) == B_OK) 190 SaveAsText(path.Path(), PREFFILE_MIMETYPE); 191 } 192 193 194 void 195 PrefHandler::SaveAsText(const char *path, const char *mimetype, 196 const char *signature) 197 { 198 // make sure the target path exists 199 #if 0 200 BPath directoryPath(path); 201 if (directoryPath.GetParent(&directoryPath) == B_OK) 202 create_directory(directoryPath.Path(), 0755); 203 #endif 204 205 BFile file(path, B_WRITE_ONLY | B_CREATE_FILE | B_ERASE_FILE); 206 char buffer[512]; 207 type_code type; 208 const char *key; 209 210 for (int32 i = 0; 211 #ifdef B_BEOS_VERSION_DANO 212 fContainer.GetInfo(B_STRING_TYPE, i, &key, &type) == B_OK; 213 #else 214 fContainer.GetInfo(B_STRING_TYPE, i, (char**)&key, &type) == B_OK; 215 #endif 216 i++) { 217 int len = snprintf(buffer, sizeof(buffer), "\"%s\" , \"%s\"\n", 218 key, getString(key)); 219 file.Write(buffer, len); 220 } 221 222 if (mimetype != NULL) { 223 BNodeInfo info(&file); 224 info.SetType(mimetype); 225 info.SetPreferredApp(signature); 226 } 227 } 228 229 230 int32 231 PrefHandler::getInt32(const char *key) 232 { 233 const char *value = fContainer.FindString(key); 234 if (value == NULL) 235 return 0; 236 237 return atoi(value); 238 } 239 240 241 float 242 PrefHandler::getFloat(const char *key) 243 { 244 const char *value = fContainer.FindString(key); 245 if (value == NULL) 246 return 0; 247 248 return atof(value); 249 } 250 251 252 #undef B_TRANSLATION_CONTEXT 253 #define B_TRANSLATION_CONTEXT "Terminal getString" 254 255 const char* 256 PrefHandler::getString(const char *key) 257 { 258 const char *buffer; 259 if (fContainer.FindString(key, &buffer) != B_OK) 260 buffer = B_TRANSLATE("Error!"); 261 262 //printf("%x GET %s: %s\n", this, key, buf); 263 return buffer; 264 } 265 266 267 bool 268 PrefHandler::getBool(const char *key) 269 { 270 const char *value = fContainer.FindString(key); 271 if (value == NULL) 272 return false; 273 274 return strcmp(value, PREF_TRUE) == 0; 275 } 276 277 278 int 279 PrefHandler::getCursor(const char *key) 280 { 281 const char *value = fContainer.FindString(key); 282 if (value != NULL && strcmp(value, PREF_BLOCK_CURSOR) != 0) { 283 if (strcmp(value, PREF_UNDERLINE_CURSOR) == 0) 284 return UNDERLINE_CURSOR; 285 if (strcmp(value, PREF_IBEAM_CURSOR) == 0) 286 return IBEAM_CURSOR; 287 } 288 return BLOCK_CURSOR; 289 } 290 291 292 #undef B_TRANSLATION_CONTEXT 293 #define B_TRANSLATION_CONTEXT "Terminal getRGB" 294 295 /** Returns RGB data from given key. */ 296 297 rgb_color 298 PrefHandler::getRGB(const char *key) 299 { 300 rgb_color col; 301 int r, g, b; 302 303 if (const char *s = fContainer.FindString(key)) { 304 sscanf(s, "%d, %d, %d", &r, &g, &b); 305 } else { 306 fprintf(stderr, 307 "PrefHandler::getRGB(%s) - key not found\n", key); 308 r = g = b = 0; 309 } 310 311 col.red = r; 312 col.green = g; 313 col.blue = b; 314 col.alpha = 255; 315 return col; 316 } 317 318 319 /** Setting Int32 data with key. */ 320 321 void 322 PrefHandler::setInt32(const char *key, int32 data) 323 { 324 char buffer[32]; 325 snprintf(buffer, sizeof(buffer), "%d", (int)data); 326 setString(key, buffer); 327 } 328 329 330 /** Setting Float data with key */ 331 332 void 333 PrefHandler::setFloat(const char *key, float data) 334 { 335 char buffer[32]; 336 snprintf(buffer, sizeof(buffer), "%g", data); 337 setString(key, buffer); 338 } 339 340 341 /** Setting Bool data with key */ 342 343 void 344 PrefHandler::setBool(const char *key, bool data) 345 { 346 if (data) 347 setString(key, PREF_TRUE); 348 else 349 setString(key, PREF_FALSE); 350 } 351 352 353 /** Setting CString data with key */ 354 355 void 356 PrefHandler::setString(const char *key, const char *data) 357 { 358 //printf("%x SET %s: %s\n", this, key, data); 359 fContainer.RemoveName(key); 360 fContainer.AddString(key, data); 361 } 362 363 364 /** Setting RGB data with key */ 365 366 void 367 PrefHandler::setRGB(const char *key, const rgb_color data) 368 { 369 char buffer[32]; 370 snprintf(buffer, sizeof(buffer), "%d, %d, %d", data.red, data.green, data.blue); 371 setString(key, buffer); 372 } 373 374 375 /** Check any peference stored or not. */ 376 377 bool 378 PrefHandler::IsEmpty() const 379 { 380 return fContainer.IsEmpty(); 381 } 382 383 384 void 385 PrefHandler::_ConfirmFont(const BFont *fallbackFont) 386 { 387 font_family family; 388 font_style style; 389 390 const char *prefFamily = getString(PREF_HALF_FONT_FAMILY); 391 int32 familiesCount = (prefFamily != NULL) ? count_font_families() : 0; 392 393 for (int32 i = 0; i < familiesCount; i++) { 394 if (get_font_family(i, &family) != B_OK 395 || strcmp(family, prefFamily) != 0) 396 continue; 397 398 const char *prefStyle = getString(PREF_HALF_FONT_STYLE); 399 int32 stylesCount = (prefStyle != NULL) ? count_font_styles(family) : 0; 400 401 for (int32 j = 0; j < stylesCount; j++) { 402 // check style if we can safely use this font 403 if (get_font_style(family, j, &style) == B_OK 404 && strcmp(style, prefStyle) == 0) 405 return; 406 } 407 } 408 409 // use fall-back font 410 fallbackFont->GetFamilyAndStyle(&family, &style); 411 setString(PREF_HALF_FONT_FAMILY, family); 412 setString(PREF_HALF_FONT_STYLE, style); 413 } 414 415 416 status_t 417 PrefHandler::_LoadFromDefault(const pref_defaults* defaults) 418 { 419 if (defaults == NULL) 420 return B_ERROR; 421 422 while (defaults->key) { 423 setString(defaults->key, defaults->item); 424 ++defaults; 425 } 426 427 return B_OK; 428 } 429 430 431 /** Text is "key","Content" 432 * Comment : Start with '#' 433 */ 434 435 status_t 436 PrefHandler::_LoadFromTextFile(const char * path) 437 { 438 char buffer[1024]; 439 char key[B_FIELD_NAME_LENGTH], data[512]; 440 int n; 441 FILE *file; 442 443 file = fopen(path, "r"); 444 if (file == NULL) 445 return B_ENTRY_NOT_FOUND; 446 447 while (fgets(buffer, sizeof(buffer), file) != NULL) { 448 if (*buffer == '#') 449 continue; 450 451 n = sscanf(buffer, "%*[\"]%[^\"]%*[\"]%*[^\"]%*[\"]%[^\"]", key, data); 452 if (n == 2) 453 setString(key, data); 454 } 455 456 fclose(file); 457 return B_OK; 458 } 459