Vault  4.1
vcolor.cpp
00001 
00002 /*
00003 Copyright c1997-2014 Trygve Isaacson. All rights reserved.
00004 This file is part of the Code Vault version 4.1
00005 http://www.bombaydigital.com/
00006 License: MIT. See LICENSE.md in the Vault top level directory.
00007 */
00008 
00009 #include "vcolor.h"
00010 
00011 #include "vchar.h"
00012 #include "vhex.h"
00013 #include "vsettings.h"
00014 
00015 // VColor ------------------------------------------------------------------
00016 
00017 // The standard CSS named colors.
00018 const VColor& VColor::AQUA()    { static const VColor kAqua   (  0, 255, 255); return kAqua; }
00019 const VColor& VColor::BLACK()   { static const VColor kBlack  (  0,   0,   0); return kBlack; }
00020 const VColor& VColor::BLUE()    { static const VColor kBlue   (  0,   0, 255); return kBlue; }
00021 const VColor& VColor::FUCHSIA() { static const VColor kFuchsia(255,   0, 255); return kFuchsia; }
00022 const VColor& VColor::GREEN()   { static const VColor kGreen  (  0, 128,   0); return kGreen; }
00023 const VColor& VColor::GRAY()    { static const VColor kGray   (128, 128, 128); return kGray; }
00024 const VColor& VColor::LIME()    { static const VColor kLime   (  0, 255,   0); return kLime; }
00025 const VColor& VColor::MAROON()  { static const VColor kMaroon (128,   0,   0); return kMaroon; }
00026 const VColor& VColor::NAVY()    { static const VColor kNavy   (  0,   0, 128); return kNavy; }
00027 const VColor& VColor::OLIVE()   { static const VColor kOlive  (128, 128,   0); return kOlive; }
00028 const VColor& VColor::ORANGE()  { static const VColor kOrange (255, 165,   0); return kOrange; }
00029 const VColor& VColor::PURPLE()  { static const VColor kPurple (128,   0, 128); return kPurple; }
00030 const VColor& VColor::RED()     { static const VColor kRed    (255,   0,   0); return kRed; }
00031 const VColor& VColor::SILVER()  { static const VColor kSilver (192, 192, 192); return kSilver; }
00032 const VColor& VColor::TEAL()    { static const VColor kTeal   (  0, 128, 128); return kTeal; }
00033 const VColor& VColor::WHITE()   { static const VColor kWhite  (255, 255, 255); return kWhite; }
00034 const VColor& VColor::YELLOW()  { static const VColor kYellow (255, 255,   0); return kYellow; }
00035 
00036 VString VColor::getCSSColor() const {
00037     if (*this == BLACK())
00038         return "black";
00039     if (*this == WHITE())
00040         return "white";
00041 
00042     if (*this == AQUA())
00043         return "aqua";
00044     if (*this == BLUE())
00045         return "blue";
00046     if (*this == FUCHSIA())
00047         return "fuchsia";
00048     if (*this == GREEN())
00049         return "green";
00050     if (*this == GRAY())
00051         return "gray";
00052     if (*this == LIME())
00053         return "lime";
00054     if (*this == MAROON())
00055         return "maroon";
00056     if (*this == NAVY())
00057         return "navy";
00058     if (*this == OLIVE())
00059         return "olive";
00060     if (*this == ORANGE())
00061         return "orange";
00062     if (*this == PURPLE())
00063         return "purple";
00064     if (*this == RED())
00065         return "red";
00066     if (*this == SILVER())
00067         return "silver";
00068     if (*this == TEAL())
00069         return "teal";
00070     if (*this == YELLOW())
00071         return "yellow";
00072 
00073     return VSTRING_FORMAT("#%02x%02x%02x", mRed, mGreen, mBlue);
00074 }
00075 
00076 VDouble VColor::getLightness() const {
00077     // Calculate the Lightness value (the L in HSL; doesn't require calculating H or S).
00078     Vu8 maxColor = V_MAX(mRed, V_MAX(mGreen, mBlue));
00079     Vu8 minColor = V_MIN(mRed, V_MIN(mGreen, mBlue));
00080     VDouble lightness = (((VDouble) minColor) + ((VDouble) maxColor)) / 510.0; // e.g., avg of minColor and maxColor, where 0 is 0.0 and 255 is 1.0, thus divide by (2*255)
00081     return lightness;
00082 }
00083 
00084 void VColor::setCSSColor(const VString& cssColor) {
00085     VString colorText(cssColor);
00086     colorText.trim(); // allow for leading/trailing whitespace in input string
00087 
00088     bool valid = false;
00089     if (colorText.startsWith('#')) {
00090         // Allowed formats:
00091         // #xyz is short for #xxyyzz
00092         // #xxyyzz is the hexadecimal r-g-b byte values
00093         if (colorText.length() == 4) {
00094             valid = colorText.at(1).isHexadecimal() &&
00095                     colorText.at(2).isHexadecimal() &&
00096                     colorText.at(3).isHexadecimal();
00097 
00098             if (valid) {
00099                 mRed = VHex::hexCharsToByte(colorText.at(1), colorText.at(1));
00100                 mGreen = VHex::hexCharsToByte(colorText.at(2), colorText.at(2));
00101                 mBlue = VHex::hexCharsToByte(colorText.at(3), colorText.at(3));
00102                 mAlpha = 255;
00103             }
00104         } else if (colorText.length() == 7) {
00105             valid = colorText.at(1).isHexadecimal() &&
00106                     colorText.at(2).isHexadecimal() &&
00107                     colorText.at(3).isHexadecimal() &&
00108                     colorText.at(4).isHexadecimal() &&
00109                     colorText.at(5).isHexadecimal() &&
00110                     colorText.at(6).isHexadecimal();
00111 
00112             if (valid) {
00113                 mRed = VHex::hexCharsToByte(colorText.at(1), colorText.at(2));
00114                 mGreen = VHex::hexCharsToByte(colorText.at(3), colorText.at(4));
00115                 mBlue = VHex::hexCharsToByte(colorText.at(5), colorText.at(6));
00116                 mAlpha = 255;
00117             }
00118         }
00119     } else if (colorText.startsWith("rgb(") && colorText.endsWith(')')) {
00120         // Allowed formats:
00121         // rgb(x,y,z) -- whitespace inside () is OK; x y and z are the r, g, b integer values
00122         colorText.substringInPlace(4, colorText.length() - 1);
00123         colorText.trim();
00124         int redStart = 0;
00125         int redEnd = colorText.indexOf(',');
00126         int greenStart = redEnd + 1;
00127         int greenEnd = colorText.indexOf(',', greenStart);
00128         int blueStart = greenEnd + 1;
00129         int blueEnd = colorText.indexOf(',', blueStart);
00130 
00131         if ((redStart < redEnd) && (redEnd < greenStart) && (greenStart < greenEnd) && (greenEnd < blueStart) && (blueEnd == -1)) {
00132             VString redValue; colorText.getSubstring(redValue, redStart, redEnd); redValue.trim();
00133             VString greenValue; colorText.getSubstring(greenValue, greenStart, greenEnd); greenValue.trim();
00134             VString blueValue; colorText.getSubstring(blueValue, blueStart, blueEnd); blueValue.trim();
00135 
00136             if (redValue.isNotEmpty() && greenValue.isNotEmpty() && blueValue.isNotEmpty()) { // parseInt() treats empty as meaning "0"
00137                 try {
00138                     int r = redValue.parseInt();
00139                     int g = greenValue.parseInt();
00140                     int b = blueValue.parseInt();
00141                     this->setValues(r, g, b);
00142                     valid = true;
00143                 } catch (VRangeException& /*ex*/) {
00144                     // Let our validity check below throw with a more informative message than "integer value out of range".
00145                 }
00146             }
00147         }
00148     } else if (colorText.equalsIgnoreCase("black")) {
00149         *this = BLACK();
00150         valid = true;
00151     } else if (colorText.equalsIgnoreCase("white")) {
00152         *this = WHITE();
00153         valid = true;
00154     } else if (colorText.equalsIgnoreCase("aqua") || colorText.equalsIgnoreCase("cyan")) {
00155         *this = AQUA();
00156         valid = true;
00157     } else if (colorText.equalsIgnoreCase("blue")) {
00158         *this = BLUE();
00159         valid = true;
00160     } else if (colorText.equalsIgnoreCase("fuchsia") || colorText.equalsIgnoreCase("magenta")) {
00161         *this = FUCHSIA();
00162         valid = true;
00163     } else if (colorText.equalsIgnoreCase("green")) {
00164         *this = GREEN();
00165         valid = true;
00166     } else if (colorText.equalsIgnoreCase("gray") || colorText.equalsIgnoreCase("grey")) {
00167         *this = GRAY();
00168         valid = true;
00169     } else if (colorText.equalsIgnoreCase("lime")) {
00170         *this = LIME();
00171         valid = true;
00172     } else if (colorText.equalsIgnoreCase("maroon")) {
00173         *this = MAROON();
00174         valid = true;
00175     } else if (colorText.equalsIgnoreCase("navy")) {
00176         *this = NAVY();
00177         valid = true;
00178     } else if (colorText.equalsIgnoreCase("olive")) {
00179         *this = OLIVE();
00180         valid = true;
00181     } else if (colorText.equalsIgnoreCase("orange")) {
00182         *this = ORANGE();
00183         valid = true;
00184     } else if (colorText.equalsIgnoreCase("purple")) {
00185         *this = PURPLE();
00186         valid = true;
00187     } else if (colorText.equalsIgnoreCase("red")) {
00188         *this = RED();
00189         valid = true;
00190     } else if (colorText.equalsIgnoreCase("silver")) {
00191         *this = SILVER();
00192         valid = true;
00193     } else if (colorText.equalsIgnoreCase("teal")) {
00194         *this = TEAL();
00195         valid = true;
00196     } else if (colorText.equalsIgnoreCase("yellow")) {
00197         *this = YELLOW();
00198         valid = true;
00199     }
00200 
00201     if (!valid)
00202         throw VRangeException(VSTRING_FORMAT("VColor::setCSSColor '%s' is invalid.", cssColor.chars()));
00203 }
00204 
00205 // VColorPair -----------------------------------------------------------------
00206 
00207 VColorPair::VColorPair()
00208     : mBg(VColor::WHITE())
00209     , mFg(VColor::BLACK())
00210     {
00211 }
00212 
00213 VColorPair::VColorPair(const VColor& bg)
00214     : mBg(bg)
00215     , mFg(VColorPair::generateContrastingForeground(bg))
00216     {
00217 }
00218 
00219 VColorPair::VColorPair(const VColor& bg, const VColor& fg)
00220     : mBg(bg)
00221     , mFg(fg)
00222     {
00223 }
00224 
00225 VString VColorPair::getCSSColor() const {
00226     return VSTRING_FORMAT("%s-on-%s", mFg.getCSSColor().chars(), mBg.getCSSColor().chars());
00227 }
00228 
00229 // static
00230 VColor VColorPair::generateContrastingForeground(const VColor& bg) {
00231     return (bg.getLightness() >= 0.5) ? VColor::BLACK() : VColor::WHITE();
00232 }
00233 
00234 // static
00235 VColorPair VColorPair::safeConstructColorPair(const VString& bgCssColor, const VString& fgCssColor) {
00236     VColor bg = VColor::WHITE();
00237     VColor fg;
00238     bool hasFg = false;
00239 
00240     if (bgCssColor.isNotEmpty()) {
00241         try {
00242             bg.setCSSColor(bgCssColor);
00243         } catch (...) {throw;}
00244     }
00245 
00246     if (fgCssColor.isNotEmpty()) {
00247         try {
00248             fg.setCSSColor(fgCssColor);
00249             hasFg = true;
00250         } catch (...) {throw;}
00251     }
00252 
00253     if (hasFg) {
00254         return VColorPair(bg, fg);
00255     }
00256 
00257     return VColorPair(bg);
00258 }
00259 
00260 // VColorPalette --------------------------------------------------------------
00261 
00262 VColorPalette::VColorPalette()
00263     : mName()
00264     , mColorMappers()
00265     , mAliases()
00266     {
00267 }
00268 
00269 VColorPalette::VColorPalette(const VSettingsNode& paletteNode, VStringVector* errorList)
00270     : mName()
00271     , mColorMappers()
00272     , mAliases()
00273     {
00274     mName = paletteNode.getString("name", mName);
00275     int numMappers = paletteNode.countNamedChildren("color-map");
00276 
00277     if ((numMappers == 0) && (errorList != NULL)) {
00278         errorList->push_back(VSTRING_FORMAT("Color palette '%s' has no color maps.", mName.chars()));
00279     }
00280 
00281     for (int i = 0; i < numMappers; ++i) {
00282         const VSettingsNode* mapperNode = paletteNode.getNamedChild("color-map", i);
00283         this->_addMapper(*mapperNode, errorList);
00284     }
00285 }
00286 
00287 VColorPalette::~VColorPalette() {
00288     // Remove all alias keys from mColorMappers, so that mapDeleteAllValues doesn't double-delete aliased objects.
00289     for (VStringVector::const_iterator i = mAliases.begin(); i != mAliases.end(); ++i) {
00290         mColorMappers[*i] = NULL;
00291     }
00292 
00293     vault::mapDeleteAllValues(mColorMappers);
00294 }
00295 
00296 void VColorPalette::adoptColorMapper(const VString& mapperName, VColorMapper* mapper) {
00297     VColorMapper* existingMapper = mColorMappers[mapperName];
00298     delete existingMapper;
00299     mColorMappers[mapperName] = mapper;
00300 }
00301 
00302 const VColorMapper* VColorPalette::findMapper(const VString& mapperName) const {
00303     VColorPaletteMap::const_iterator position = mColorMappers.find(mapperName);
00304     if (position == mColorMappers.end()) {
00305         return NULL;
00306     }
00307 
00308     VColorMapper* result = (*position).second;
00309     return result;
00310 }
00311 
00312 VColorPair VColorPalette::getColors(const VString& mapperName, const VString& stringValue) const {
00313     const VColorMapper* cm = this->findMapper(mapperName);
00314     if (cm == NULL) {
00315         return VColorPair();
00316     }
00317 
00318     return cm->getColors(stringValue);
00319 }
00320 
00321 VColorPair VColorPalette::getColors(const VString& mapperName, int intValue) const {
00322     const VColorMapper* cm = this->findMapper(mapperName);
00323     if (cm == NULL) {
00324         return VColorPair();
00325     }
00326 
00327     return cm->getColors(intValue);
00328 }
00329 
00330 VColorPair VColorPalette::getColors(const VString& mapperName, Vs64 int64Value) const {
00331     const VColorMapper* cm = this->findMapper(mapperName);
00332     if (cm == NULL) {
00333         return VColorPair();
00334     }
00335 
00336     return cm->getColors(int64Value);
00337 }
00338 
00339 VColorPair VColorPalette::getColors(const VString& mapperName, VDouble doubleValue) const {
00340     const VColorMapper* cm = this->findMapper(mapperName);
00341     if (cm == NULL) {
00342         return VColorPair();
00343     }
00344 
00345     return cm->getColors(doubleValue);
00346 }
00347 
00348 void VColorPalette::_addMapper(const VSettingsNode& mapperNode, VStringVector* errorList) {
00349     try {
00350         VString mapperName = mapperNode.getString("name");
00351         VString mapperType = mapperNode.getString("type", "string-values");
00352         bool usesPrefixMode = mapperNode.getBoolean("prefix-mode", false);
00353         VColorMapper* mapper = this->_readNewMapper(mapperType, mapperNode, usesPrefixMode, errorList);
00354 
00355         if (mapper != NULL) {
00356             // For now, we assume the palette is initialized and never subsequently modified.
00357             // So we don't look for an existing mapper to delete/replace.
00358             mColorMappers[mapperName] = mapper;
00359 
00360             this->_addMapperNameAliases(mapper, mapperNode, errorList);
00361         }
00362     } catch (const std::exception& ex) {
00363         if (errorList != NULL) {
00364             errorList->push_back(VSTRING_FORMAT("At %s/%s: %s", mapperNode.getPath().chars(), mapperNode.getString("name", "").chars(), ex.what()));
00365         }
00366     }
00367 }
00368 
00369 VColorMapper* VColorPalette::_readNewMapper(const VString& mapperType, const VSettingsNode& mapperNode, bool usesPrefixMode, VStringVector* errorList) {
00370     VColorMapper* mapper = NULL;
00371     if (mapperType == "string-values") {
00372         if (usesPrefixMode) {
00373             mapper = new VStringRangeColorMapper(usesPrefixMode);
00374         } else {
00375             mapper = new VStringColorMapper();
00376         }
00377     } else if (mapperType == "integer-values") {
00378         mapper = new VIntegerColorMapper();
00379     } else if (mapperType == "real-values") {
00380         mapper = new VDoubleColorMapper();
00381     } else if (mapperType == "string-ranges") {
00382         mapper = new VStringRangeColorMapper(usesPrefixMode);
00383     } else if (mapperType == "integer-ranges") {
00384         mapper = new VIntegerRangeColorMapper();
00385     } else if (mapperType == "real-ranges") {
00386         mapper = new VDoubleRangeColorMapper();
00387     } else if (errorList != NULL) {
00388         errorList->push_back(VSTRING_FORMAT("At %s/%s: Invalid color-map type '%s'.", mapperNode.getPath().chars(), mapperNode.getString("name", "").chars(), mapperType.chars()));
00389     }
00390 
00391     if (mapper != NULL) {
00392         mapper->readColors(mapperNode, errorList);
00393     }
00394 
00395     return mapper;
00396 }
00397 
00398 void VColorPalette::_addMapperNameAliases(VColorMapper* mapper, const VSettingsNode& mapperNode, VStringVector* errorList) {
00399     bool mapperUsesPrefixMode = mapperNode.getBoolean("prefix-mode", false);
00400     int numAliases = mapperNode.countNamedChildren("alias");
00401     for (int i = 0; i < numAliases; ++i) {
00402         const VSettingsNode* aliasNode = mapperNode.getNamedChild("alias", i);
00403         VString alias = aliasNode->getString("name", VString::EMPTY());
00404         if (alias.isNotEmpty()) {
00405             // If the alias uses a different prefix-mode flag than the original mapper, need a separate instance,
00406             // since behavior is totally different. In that case it's not really an "alias" we need to track, it
00407             // is really another independent mapper.
00408             bool aliasUsesPrefixMode = aliasNode->getBoolean("prefix-mode", false);
00409             if (aliasUsesPrefixMode == mapperUsesPrefixMode) {
00410                 mAliases.push_back(alias);
00411             } else {
00412                 mapper = this->_readNewMapper(mapperNode.getString("type", "string-values"), mapperNode, aliasUsesPrefixMode, errorList);
00413             }
00414 
00415             mColorMappers[alias] = mapper;
00416         }
00417     }
00418 }
00419 
00420 // VColorMapper ---------------------------------------------------------------
00421 
00422 void VColorMapper::readColors(const VSettingsNode& mapperNode, VStringVector* errorList) {
00423     VString defaultBg = mapperNode.getString("default-bg", VString::EMPTY());
00424     VString defaultFg = mapperNode.getString("default-fg", VString::EMPTY());
00425     if (defaultBg.isNotEmpty() || defaultFg.isNotEmpty()) {
00426         this->setDefaultColors(VColorPair::safeConstructColorPair(defaultBg, defaultFg));
00427     }
00428 
00429     int numColors = mapperNode.countNamedChildren("color");
00430 
00431     if ((numColors == 0) && (errorList != NULL)) {
00432         errorList->push_back(VSTRING_FORMAT("At %s/%s: No colors defined in color-map.", mapperNode.getPath().chars(), mapperNode.getString("name", "").chars()));
00433     }
00434 
00435     for (int i = 0; i < numColors; ++i) {
00436         const VSettingsNode* colorNode = mapperNode.getNamedChild("color", i);
00437 
00438         try {
00439             this->_readColorElement(*colorNode);
00440         } catch (const std::exception& ex) {
00441             if (errorList != NULL) {
00442                 errorList->push_back(VSTRING_FORMAT("At %s/%s: Error reading color value [%d]: %s", mapperNode.getPath().chars(), mapperNode.getString("name", "").chars(), i, ex.what()));
00443             }
00444         }
00445     }
00446 }
00447 
00448 VColorPair VColorMapper::_readColorPair(const VSettingsNode& colorNode) {
00449     VString bg = colorNode.getString("bg", VString::EMPTY());
00450     VString fg = colorNode.getString("fg", VString::EMPTY());
00451     return VColorPair::safeConstructColorPair(bg, fg);
00452 }
00453 
00454 // VStringColorMapper ---------------------------------------------------------
00455 
00456 VStringColorMapper::VStringColorMapper()
00457     : VColorMapper()
00458     , mColorMap()
00459     , mCaseSensitive(false)
00460     {
00461 }
00462 
00463 VStringColorMapper::~VStringColorMapper() {
00464 }
00465 
00466 void VStringColorMapper::readColors(const VSettingsNode& mapperNode, VStringVector* errorList) {
00467     mCaseSensitive = mapperNode.getBoolean("case-sensitive", mCaseSensitive);
00468     VColorMapper::readColors(mapperNode, errorList);
00469 }
00470 
00471 VColorPair VStringColorMapper::getColors(const VString& stringValue) const {
00472     VString key(stringValue);
00473     if (!mCaseSensitive) {
00474         key.toLowerCase();
00475     }
00476 
00477     VStringColorMap::const_iterator position = mColorMap.find(key);
00478     if (position == mColorMap.end()) {
00479         return mDefaultColors;
00480     }
00481 
00482     return (*position).second;
00483 }
00484 
00485 VColorPair VStringColorMapper::getColors(int intValue) const {
00486     return this->getColors(VSTRING_INT(intValue));
00487 }
00488 
00489 VColorPair VStringColorMapper::getColors(Vs64 int64Value) const {
00490     return this->getColors(VSTRING_S64(int64Value));
00491 }
00492 
00493 VColorPair VStringColorMapper::getColors(VDouble doubleValue) const {
00494     return this->getColors(VSTRING_DOUBLE(doubleValue));
00495 }
00496 
00497 void VStringColorMapper::addColors(const VString& stringValue, const VColorPair& colors) {
00498     VString key(stringValue);
00499     if (!mCaseSensitive) {
00500         key.toLowerCase();
00501     }
00502 
00503     mColorMap[key] = colors;
00504 }
00505 
00506 void VStringColorMapper::_readColorElement(const VSettingsNode& colorNode) {
00507     this->addColors(colorNode.getString("value"), this->_readColorPair(colorNode));
00508 }
00509 
00510 // VIntegerColorMapper --------------------------------------------------------
00511 
00512 VIntegerColorMapper::VIntegerColorMapper()
00513     : VColorMapper()
00514     , mColorMap()
00515     {
00516 }
00517 
00518 VIntegerColorMapper::~VIntegerColorMapper() {
00519 }
00520 
00521 VColorPair VIntegerColorMapper::getColors(const VString& stringValue) const {
00522     try {
00523         Vs64 int64Value = stringValue.parseS64();
00524         return this->getColors(int64Value);
00525     } catch (...) {} // Will occur if the string is not a parseable integer.
00526 
00527     return mDefaultColors;
00528 }
00529 
00530 VColorPair VIntegerColorMapper::getColors(int intValue) const {
00531     Vs64 int64Value = intValue;
00532     return this->getColors(int64Value);
00533 }
00534 
00535 VColorPair VIntegerColorMapper::getColors(Vs64 int64Value) const {
00536     VIntegerColorMap::const_iterator position = mColorMap.find(int64Value);
00537     if (position == mColorMap.end()) {
00538         return mDefaultColors;
00539     }
00540 
00541     return (*position).second;
00542 }
00543 
00544 VColorPair VIntegerColorMapper::getColors(VDouble doubleValue) const {
00545     // No perfect way to know what a generic caller expects here; they really should
00546     // be using VDoubleColorMapper or VDoubleRangeColorMapper if they don't like this behavior.
00547     // We choose to truncate double to integer, and use that.
00548     // The effect is that 3, 3.0. 3.1, 3.14, etc. will all have the same output.
00549 
00550     Vs64 int64Value = static_cast<Vs64>(doubleValue);
00551     return this->getColors(int64Value);
00552 }
00553 
00554 void VIntegerColorMapper::addColors(Vs64 intValue, const VColorPair& colors) {
00555     mColorMap[intValue] = colors;
00556 }
00557 
00558 void VIntegerColorMapper::_readColorElement(const VSettingsNode& colorNode) {
00559     this->addColors(colorNode.getS64("value"), this->_readColorPair(colorNode));
00560 }
00561 
00562 // VDoubleColorMapper ---------------------------------------------------------
00563 
00564 VDoubleColorMapper::VDoubleColorMapper()
00565     : VColorMapper()
00566     , mColorMap()
00567     {
00568 }
00569 
00570 VDoubleColorMapper::~VDoubleColorMapper() {
00571 }
00572 
00573 VColorPair VDoubleColorMapper::getColors(const VString& stringValue) const {
00574     try {
00575         VDouble doubleValue = stringValue.parseDouble();
00576         return this->getColors(doubleValue);
00577     } catch (...) {} // Will occur if the string is not a parseable double.
00578 
00579     return mDefaultColors;
00580 }
00581 
00582 VColorPair VDoubleColorMapper::getColors(int intValue) const {
00583     VDouble doubleValue = static_cast<VDouble>(intValue);
00584     return this->getColors(doubleValue);
00585 }
00586 
00587 VColorPair VDoubleColorMapper::getColors(Vs64 int64Value) const {
00588     VDouble doubleValue = static_cast<VDouble>(int64Value);
00589     return this->getColors(doubleValue);
00590 }
00591 
00592 VColorPair VDoubleColorMapper::getColors(VDouble doubleValue) const {
00593     VStringColorMap::const_iterator position = mColorMap.find(VSTRING_DOUBLE(doubleValue));
00594     if (position == mColorMap.end()) {
00595         return mDefaultColors;
00596     }
00597 
00598     return (*position).second;
00599 }
00600 
00601 void VDoubleColorMapper::addColors(VDouble doubleValue, const VColorPair& colors) {
00602     mColorMap[VSTRING_DOUBLE(doubleValue)] = colors;
00603 }
00604 
00605 void VDoubleColorMapper::_readColorElement(const VSettingsNode& colorNode) {
00606     this->addColors(colorNode.getDouble("value"), this->_readColorPair(colorNode));
00607 }
00608 
00609 // VStringRangeColorMapper --------------------------------------------------------
00610 
00611 VStringRangeColorMapper::VStringRangeColorMapper(bool usesPrefixMode)
00612     : VColorMapper()
00613     , mColorRanges()
00614     , mCaseSensitive(false)
00615     , mUsesPrefixMode(usesPrefixMode)
00616     {
00617 }
00618 
00619 VStringRangeColorMapper::~VStringRangeColorMapper() {
00620 }
00621 
00622 void VStringRangeColorMapper::readColors(const VSettingsNode& mapperNode, VStringVector* errorList) {
00623     mCaseSensitive = mapperNode.getBoolean("case-sensitive", mCaseSensitive);
00624     VColorMapper::readColors(mapperNode, errorList);
00625 }
00626 
00627 VColorPair VStringRangeColorMapper::getColors(const VString& stringValue) const {
00628     if (mColorRanges.empty())
00629         return mDefaultColors;
00630 
00631     VString caseAdjustedValue(stringValue);
00632     if (!mCaseSensitive)
00633         caseAdjustedValue.toLowerCase();
00634 
00635     // lower_bound() uses binary search, should be the fastest way.
00636     VStringRangeColorElement testValue(caseAdjustedValue, VColorPair());
00637     VStringRangeVector::const_iterator position = std::lower_bound(mColorRanges.begin(), mColorRanges.end(), testValue);
00638 
00639     // The way this works, we have to essentially decrement the position to find the spot that was "hit",
00640     // unless we got an exact match. To do this, we check if the found mRangeMin is greater than the value.
00641     if (position == mColorRanges.end())
00642         return this->_getColorsWithPrefixModeCheck((*(position - 1)).mColors);
00643 
00644     if (position == mColorRanges.begin() && position->mRangeMin > caseAdjustedValue)
00645         return mDefaultColors;
00646 
00647     if (position->mRangeMin > caseAdjustedValue)
00648         --position;
00649 
00650     return this->_getColorsWithPrefixModeCheck((*position).mColors);
00651 }
00652 
00653 static const VColorPair EMPTY_MAP_COLOR_VALUE(VColor(1, 1, 1), VColor(2, 2, 2));
00654 
00655 VColorPair VStringRangeColorMapper::_getColorsWithPrefixModeCheck(const VColorPair& foundColors) const {
00656     if (mUsesPrefixMode && (foundColors == EMPTY_MAP_COLOR_VALUE))
00657         return mDefaultColors;
00658 
00659     return foundColors;
00660 }
00661 
00662 VColorPair VStringRangeColorMapper::getColors(int intValue) const {
00663     return this->getColors(VSTRING_INT(intValue));
00664 }
00665 
00666 VColorPair VStringRangeColorMapper::getColors(Vs64 int64Value) const {
00667     return this->getColors(VSTRING_S64(int64Value));
00668 }
00669 
00670 VColorPair VStringRangeColorMapper::getColors(VDouble doubleValue) const {
00671     return this->getColors(VSTRING_DOUBLE(doubleValue));
00672 }
00673 
00674 void VStringRangeColorMapper::addColors(const VString& rangeMin, const VColorPair& rangeColors) {
00675     VString caseAdjustedValue(rangeMin);
00676     if (!mCaseSensitive) {
00677         caseAdjustedValue.toLowerCase();
00678     }
00679 
00680     VStringRangeColorElement rangeElement(caseAdjustedValue, rangeColors);
00681     VStringRangeVector::iterator position = std::lower_bound(mColorRanges.begin(), mColorRanges.end(), rangeElement);
00682     (void) mColorRanges.insert(position, rangeElement);
00683 
00684     if (mUsesPrefixMode) {
00685         VStringRangeColorElement rangeEndingElement(caseAdjustedValue + "~", EMPTY_MAP_COLOR_VALUE);
00686         VStringRangeVector::iterator nextPosition = std::lower_bound(mColorRanges.begin(), mColorRanges.end(), rangeEndingElement);
00687         (void) mColorRanges.insert(nextPosition, rangeEndingElement);
00688     }
00689 }
00690 
00691 void VStringRangeColorMapper::_readColorElement(const VSettingsNode& colorNode) {
00692     this->addColors(colorNode.getString("value"), this->_readColorPair(colorNode));
00693 }
00694 
00695 // VIntegerRangeColorMapper --------------------------------------------------------
00696 
00697 VIntegerRangeColorMapper::VIntegerRangeColorMapper()
00698     : VColorMapper()
00699     , mColorRanges()
00700     {
00701 }
00702 
00703 VIntegerRangeColorMapper::~VIntegerRangeColorMapper() {
00704 }
00705 
00706 VColorPair VIntegerRangeColorMapper::getColors(const VString& stringValue) const {
00707     try {
00708         Vs64 int64Value = stringValue.parseS64();
00709         return this->getColors(int64Value);
00710     } catch (...) {} // Will occur if the string is not a parseable integer.
00711 
00712     return mDefaultColors;
00713 }
00714 
00715 VColorPair VIntegerRangeColorMapper::getColors(int intValue) const {
00716     Vs64 int64Value = intValue;
00717     return this->getColors(int64Value);
00718 }
00719 
00720 VColorPair VIntegerRangeColorMapper::getColors(Vs64 int64Value) const {
00721     if (mColorRanges.empty())
00722         return mDefaultColors;
00723 
00724     // lower_bound() uses binary search, should be the fastest way.
00725     VIntegerRangeColorElement testValue(int64Value, VColorPair());
00726     VIntegerRangeVector::const_iterator position = std::lower_bound(mColorRanges.begin(), mColorRanges.end(), testValue);
00727 
00728     // The way this works, we have to essentially decrement the position to find the spot that was "hit",
00729     // unless we got an exact match. To do this, we check if the found mRangeMin is greater than the value.
00730     if (position == mColorRanges.end())
00731         return (position - 1)->mColors;
00732 
00733     if (position == mColorRanges.begin() && position->mRangeMin > int64Value)
00734         return mDefaultColors;
00735 
00736     if (position->mRangeMin > int64Value)
00737         --position;
00738 
00739     return position->mColors;
00740 }
00741 
00742 VColorPair VIntegerRangeColorMapper::getColors(VDouble doubleValue) const {
00743     Vs64 int64Value = static_cast<Vs64>(doubleValue);
00744     return this->getColors(int64Value);
00745 }
00746 
00747 void VIntegerRangeColorMapper::addColors(Vs64 rangeMin, const VColorPair& rangeColors) {
00748     VIntegerRangeColorElement rangeElement(rangeMin, rangeColors);
00749     VIntegerRangeVector::iterator position = std::lower_bound(mColorRanges.begin(), mColorRanges.end(), rangeElement);
00750     (void) mColorRanges.insert(position, rangeElement);
00751 }
00752 
00753 void VIntegerRangeColorMapper::_readColorElement(const VSettingsNode& colorNode) {
00754     this->addColors(colorNode.getInt("value"), this->_readColorPair(colorNode));
00755 }
00756 
00757 // VDoubleRangeColorMapper --------------------------------------------------------
00758 
00759 VDoubleRangeColorMapper::VDoubleRangeColorMapper()
00760     : VColorMapper()
00761     , mColorRanges()
00762     {
00763 }
00764 
00765 VDoubleRangeColorMapper::~VDoubleRangeColorMapper() {
00766 }
00767 
00768 VColorPair VDoubleRangeColorMapper::getColors(const VString& stringValue) const {
00769     try {
00770         VDouble doubleValue = stringValue.parseDouble();
00771         return this->getColors(doubleValue);
00772     } catch (...) {} // Will occur if the string is not a parseable integer.
00773 
00774     return mDefaultColors;
00775 }
00776 
00777 VColorPair VDoubleRangeColorMapper::getColors(int intValue) const {
00778     VDouble doubleValue = static_cast<VDouble>(intValue);
00779     return this->getColors(doubleValue);
00780 }
00781 
00782 VColorPair VDoubleRangeColorMapper::getColors(Vs64 int64Value) const {
00783     VDouble doubleValue = static_cast<VDouble>(int64Value);
00784     return this->getColors(doubleValue);
00785 }
00786 
00787 VColorPair VDoubleRangeColorMapper::getColors(VDouble doubleValue) const {
00788     if (mColorRanges.empty())
00789         return mDefaultColors;
00790 
00791     // lower_bound() uses binary search, should be the fastest way.
00792     VDoubleRangeColorElement testValue(doubleValue, VColorPair());
00793     VDoubleRangeVector::const_iterator position = std::lower_bound(mColorRanges.begin(), mColorRanges.end(), testValue);
00794 
00795     // The way this works, we have to essentially decrement the position to find the spot that was "hit",
00796     // unless we got an exact match. To do this, we check if the found mRangeMin is greater than the value.
00797     if (position == mColorRanges.end())
00798         return (position - 1)->mColors;
00799 
00800     if (position == mColorRanges.begin() && position->mRangeMin > doubleValue)
00801         return mDefaultColors;
00802 
00803     if (position->mRangeMin > doubleValue)
00804         --position;
00805 
00806     return position->mColors;
00807 }
00808 
00809 void VDoubleRangeColorMapper::addColors(VDouble rangeMin, const VColorPair& rangeColors) {
00810     VDoubleRangeColorElement rangeElement(rangeMin, rangeColors);
00811     VDoubleRangeVector::iterator position = std::lower_bound(mColorRanges.begin(), mColorRanges.end(), rangeElement);
00812     (void) mColorRanges.insert(position, rangeElement);
00813 }
00814 
00815 void VDoubleRangeColorMapper::_readColorElement(const VSettingsNode& colorNode) {
00816     this->addColors(colorNode.getDouble("value"), this->_readColorPair(colorNode));
00817 }

Copyright ©1997-2014 Trygve Isaacson. All rights reserved. This documentation was generated with Doxygen.