2 * Copyright (C) 2005-2013 Team XBMC
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, see
17 * <http://www.gnu.org/licenses/>.
21 #include "GUIInfoTypes.h"
22 #include "GUIInfoManager.h"
23 #include "addons/AddonManager.h"
24 #include "utils/log.h"
25 #include "LocalizeStrings.h"
26 #include "GUIColorManager.h"
27 #include "GUIListItem.h"
28 #include "utils/StringUtils.h"
29 #include "addons/Skin.h"
32 using ADDON::CAddonMgr;
34 CGUIInfoBool::CGUIInfoBool(bool value)
39 CGUIInfoBool::~CGUIInfoBool()
43 void CGUIInfoBool::Parse(const CStdString &expression, int context)
45 if (expression == "true")
47 else if (expression == "false")
51 m_info = g_infoManager.Register(expression, context);
56 void CGUIInfoBool::Update(const CGUIListItem *item /*= NULL*/)
59 m_value = m_info->Get(item);
63 CGUIInfoColor::CGUIInfoColor(uint32_t color)
69 CGUIInfoColor &CGUIInfoColor::operator=(color_t color)
76 CGUIInfoColor &CGUIInfoColor::operator=(const CGUIInfoColor &color)
78 m_color = color.m_color;
79 m_info = color.m_info;
83 bool CGUIInfoColor::Update()
86 return false; // no infolabel
88 // Expand the infolabel, and then convert it to a color
89 CStdString infoLabel(g_infoManager.GetLabel(m_info));
90 color_t color = !infoLabel.empty() ? g_colorManager.GetColor(infoLabel.c_str()) : 0;
100 void CGUIInfoColor::Parse(const CStdString &label, int context)
102 // Check for the standard $INFO[] block layout, and strip it if present
103 CStdString label2 = label;
104 if (label.Equals("-", false))
107 if (StringUtils::StartsWithNoCase(label, "$var["))
109 label2 = label.substr(5, label.length() - 6);
110 m_info = g_infoManager.TranslateSkinVariableString(label2, context);
112 m_info = g_infoManager.RegisterSkinVariableString(g_SkinInfo->CreateSkinVariable(label2, context));
116 if (StringUtils::StartsWithNoCase(label, "$info["))
117 label2 = label.substr(6, label.length()-7);
119 m_info = g_infoManager.TranslateString(label2);
121 m_color = g_colorManager.GetColor(label);
124 CGUIInfoLabel::CGUIInfoLabel()
128 CGUIInfoLabel::CGUIInfoLabel(const CStdString &label, const CStdString &fallback /*= ""*/, int context /*= 0*/)
130 SetLabel(label, fallback, context);
133 void CGUIInfoLabel::SetLabel(const CStdString &label, const CStdString &fallback, int context /*= 0*/)
135 m_fallback = fallback;
136 Parse(label, context);
139 CStdString CGUIInfoLabel::GetLabel(int contextWindow, bool preferImage, CStdString *fallback /*= NULL*/) const
142 for (unsigned int i = 0; i < m_info.size(); i++)
144 const CInfoPortion &portion = m_info[i];
147 CStdString infoLabel;
149 infoLabel = g_infoManager.GetImage(portion.m_info, contextWindow, fallback);
150 if (infoLabel.empty())
151 infoLabel = g_infoManager.GetLabel(portion.m_info, contextWindow, fallback);
152 if (!infoLabel.empty())
153 label += portion.GetLabel(infoLabel);
156 { // no info, so just append the prefix
157 label += portion.m_prefix;
160 if (label.empty()) // empty label, use the fallback
165 CStdString CGUIInfoLabel::GetItemLabel(const CGUIListItem *item, bool preferImages, CStdString *fallback /*= NULL*/) const
167 if (!item->IsFileItem()) return "";
169 for (unsigned int i = 0; i < m_info.size(); i++)
171 const CInfoPortion &portion = m_info[i];
174 CStdString infoLabel;
176 infoLabel = g_infoManager.GetItemImage((const CFileItem *)item, portion.m_info, fallback);
178 infoLabel = g_infoManager.GetItemLabel((const CFileItem *)item, portion.m_info, fallback);
179 if (!infoLabel.empty())
180 label += portion.GetLabel(infoLabel);
183 { // no info, so just append the prefix
184 label += portion.m_prefix;
192 bool CGUIInfoLabel::IsEmpty() const
194 return m_info.size() == 0;
197 bool CGUIInfoLabel::IsConstant() const
199 return m_info.size() == 0 || (m_info.size() == 1 && m_info[0].m_info == 0);
202 CStdString CGUIInfoLabel::ReplaceLocalize(const CStdString &label)
204 CStdString work(label);
205 // Replace all $LOCALIZE[number] with the real string
206 size_t pos1 = work.find("$LOCALIZE[");
207 while (pos1 != std::string::npos)
209 size_t pos2 = StringUtils::FindEndBracket(work, '[', ']', pos1 + 10);
210 if (pos2 != std::string::npos)
212 CStdString left = work.substr(0, pos1);
213 CStdString right = work.substr(pos2 + 1);
214 CStdString replace = g_localizeStringsTemp.Get(atoi(work.substr(pos1 + 10).c_str()));
216 replace = g_localizeStrings.Get(atoi(work.substr(pos1 + 10).c_str()));
217 work = left + replace + right;
221 CLog::Log(LOGERROR, "Error parsing label - missing ']' in \"%s\"", label.c_str());
224 pos1 = work.find("$LOCALIZE[", pos1);
229 CStdString CGUIInfoLabel::ReplaceAddonStrings(const CStdString &label)
231 CStdString work(label);
232 //FIXME why not use RE here?
233 // Replace all $ADDON[id number] with the real string
234 size_t pos1 = work.find("$ADDON[");
235 while (pos1 != std::string::npos)
237 size_t pos2 = StringUtils::FindEndBracket(work, '[', ']', pos1 + 7);
238 if (pos2 != std::string::npos)
240 CStdString left = work.substr(0, pos1);
241 CStdString right = work.substr(pos2 + 1);
242 size_t length = work.find(" ", pos1 + 7) - (pos1 + 7);
243 CStdString id = work.substr(pos1 + 7, length);
244 int stringid = atoi(work.substr(pos1 + 7 + id.length() + 1, 5).c_str());
245 CStdString replace = CAddonMgr::Get().GetString(id, stringid);
246 work = left + replace + right;
250 CLog::Log(LOGERROR, "Error parsing label - missing ']' in \"%s\"", label.c_str());
253 pos1 = work.find("$ADDON[", pos1);
258 enum EINFOFORMAT { NONE = 0, FORMATINFO, FORMATESCINFO, FORMATVAR };
266 const static infoformat infoformatmap[] = {{ "$INFO[", FORMATINFO },
267 { "$ESCINFO[", FORMATESCINFO},
268 { "$VAR[", FORMATVAR}};
270 void CGUIInfoLabel::Parse(const CStdString &label, int context)
273 // Step 1: Replace all $LOCALIZE[number] with the real string
274 CStdString work = ReplaceLocalize(label);
275 // Step 2: Replace all $ADDON[id number] with the real string
276 work = ReplaceAddonStrings(work);
277 // Step 3: Find all $INFO[info,prefix,postfix] blocks
282 size_t pos1 = work.size();
285 for (size_t i = 0; i < sizeof(infoformatmap) / sizeof(infoformat); i++)
287 pos2 = work.find(infoformatmap[i].str);
288 if (pos2 != string::npos && pos2 < pos1)
291 len = strlen(infoformatmap[i].str);
292 format = infoformatmap[i].val;
299 m_info.push_back(CInfoPortion(0, work.substr(0, pos1), ""));
301 pos2 = StringUtils::FindEndBracket(work, '[', ']', pos1 + len);
302 if (pos2 != std::string::npos)
304 // decipher the block
305 CStdString block = work.substr(pos1 + len, pos2 - pos1 - len);
306 CStdStringArray params;
307 StringUtils::SplitString(block, ",", params);
309 if (format == FORMATVAR)
311 info = g_infoManager.TranslateSkinVariableString(params[0], context);
313 info = g_infoManager.RegisterSkinVariableString(g_SkinInfo->CreateSkinVariable(params[0], context));
314 if (info == 0) // skinner didn't define this conditional label!
315 CLog::Log(LOGWARNING, "Label Formating: $VAR[%s] is not defined", params[0].c_str());
318 info = g_infoManager.TranslateString(params[0]);
319 CStdString prefix, postfix;
320 if (params.size() > 1)
322 if (params.size() > 2)
324 m_info.push_back(CInfoPortion(info, prefix, postfix, format == FORMATESCINFO));
325 // and delete it from our work string
326 work = work.substr(pos2 + 1);
330 CLog::Log(LOGERROR, "Error parsing label - missing ']' in \"%s\"", label.c_str());
335 while (format != NONE);
338 m_info.push_back(CInfoPortion(0, work, ""));
341 CGUIInfoLabel::CInfoPortion::CInfoPortion(int info, const CStdString &prefix, const CStdString &postfix, bool escaped /*= false */)
347 // filter our prefix and postfix for comma's
348 StringUtils::Replace(m_prefix, "$COMMA", ",");
349 StringUtils::Replace(m_postfix, "$COMMA", ",");
350 StringUtils::Replace(m_prefix, "$LBRACKET", "["); StringUtils::Replace(m_prefix, "$RBRACKET", "]");
351 StringUtils::Replace(m_postfix, "$LBRACKET", "["); StringUtils::Replace(m_postfix, "$RBRACKET", "]");
354 CStdString CGUIInfoLabel::CInfoPortion::GetLabel(const CStdString &info) const
356 CStdString label = m_prefix + info + m_postfix;
357 if (m_escaped) // escape all quotes and backslashes, then quote
359 StringUtils::Replace(label, "\\", "\\\\");
360 StringUtils::Replace(label, "\"", "\\\"");
361 return "\"" + label + "\"";
366 CStdString CGUIInfoLabel::GetLabel(const CStdString &label, int contextWindow /*= 0*/, bool preferImage /*= false */)
367 { // translate the label
368 CGUIInfoLabel info(label, "", contextWindow);
369 return info.GetLabel(contextWindow, preferImage);