cssedit.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364
  1. /*****************************************************************************
  2. * cssedit.cpp - QStarDict, a StarDict clone written with using Qt *
  3. * Copyright (C) 2008 Alexander Rodin *
  4. * *
  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 of the License, or *
  8. * (at your option) any later version. *
  9. * *
  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. *
  14. * *
  15. * You should have received a copy of the GNU General Public License along *
  16. * with this program; if not, write to the Free Software Foundation, Inc., *
  17. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *
  18. *****************************************************************************/
  19. #include "cssedit.h"
  20. #include <QApplication>
  21. #include <QColorDialog>
  22. namespace QStarDict
  23. {
  24. CSSEdit::CSSEdit(QWidget *parent)
  25. : QWidget(parent)
  26. {
  27. setupUi(this);
  28. connect(m_elementCombo, SIGNAL(currentIndexChanged(int)), SLOT(setCurrentElement(int)));
  29. connect(m_fontCombo, SIGNAL(currentFontChanged(const QFont&)), SLOT(propertyChanged()));
  30. connect(m_sizeSpin, SIGNAL(valueChanged(int)), SLOT(propertyChanged()));
  31. connect(m_boldButton, SIGNAL(toggled(bool)), SLOT(propertyChanged()));
  32. connect(m_italicButton, SIGNAL(toggled(bool)), SLOT(propertyChanged()));
  33. connect(m_underlineButton, SIGNAL(toggled(bool)), SLOT(propertyChanged()));
  34. connect(m_colorButton, SIGNAL(clicked()), SLOT(colorSelectClicked()));
  35. connect(m_backgroundButton, SIGNAL(clicked()), SLOT(colorSelectClicked()));
  36. }
  37. void CSSEdit::setCSS(const QString &css)
  38. {
  39. m_elements.clear();
  40. bool inBlock = false;
  41. QString element;
  42. QString currentProperty;
  43. QString currentValue;
  44. for (int i = 0; i < css.length(); ++i)
  45. {
  46. if (! inBlock)
  47. {
  48. element.clear();
  49. for (; i < css.length() && css[i] != '{'; ++i)
  50. if (! css[i].isSpace())
  51. element += css[i];
  52. if (i < css.length() && css[i] == '{')
  53. {
  54. inBlock = true;
  55. ++i;
  56. }
  57. }
  58. else
  59. {
  60. currentProperty.clear();
  61. for (; i < css.length() && css[i] != ':'; ++i)
  62. if (! css[i].isSpace())
  63. currentProperty += css[i];
  64. if (! inBlock)
  65. continue;
  66. currentValue.clear();
  67. char quote = '\0';
  68. for (++i; i < css.length() && css[i] != ';'; ++i)
  69. {
  70. if (quote)
  71. {
  72. if (css[i] == quote)
  73. {
  74. while (i < css.length() && css[i] != ';')
  75. ++i;
  76. break;
  77. }
  78. else
  79. currentValue += css[i];
  80. }
  81. else if (! css[i].isSpace())
  82. {
  83. if (css[i] == '\'' || css[i] == '\"')
  84. quote = css[i].toLatin1();
  85. else
  86. currentValue += css[i];
  87. }
  88. }
  89. m_elements[element][currentProperty] = currentValue;
  90. while (css[i + 1].isSpace())
  91. ++i;
  92. if (css[i + 1] == '}')
  93. {
  94. ++i;
  95. inBlock = false;
  96. }
  97. }
  98. }
  99. updateElementCombo();
  100. updatePreview();
  101. }
  102. void CSSEdit::setElementsAliases(const QHash<QString, QString> &aliases)
  103. {
  104. m_elementsAliases = aliases;
  105. updateElementCombo();
  106. updatePreview();
  107. }
  108. QString CSSEdit::css() const
  109. {
  110. QString result;
  111. for (QHash<QString, Element>::const_iterator i = m_elements.begin(); i != m_elements.end(); ++i)
  112. {
  113. result += i.key() + "\n{\n";
  114. for (Element::const_iterator j = i->begin(); j != i->end(); ++j)
  115. {
  116. result += j.key() + ": ";
  117. if (j->contains(' '))
  118. result += "\"" + *j + "\";\n";
  119. else
  120. result += *j + ";\n";
  121. }
  122. result += "}\n";
  123. }
  124. return result;
  125. }
  126. void CSSEdit::setCurrentElement(int index)
  127. {
  128. if (! m_elements.contains(m_elementCombo->itemData(index).toString()))
  129. return;
  130. m_currentElement = m_elementCombo->itemData(index).toString();
  131. Element *element = &m_elements[m_currentElement];
  132. Element parentElement = getParentElement(m_currentElement);
  133. QColor color(element->contains("color") ? element->value("color") : parentElement["color"]);
  134. m_colorButton->setText(color.name());
  135. QPalette palette = m_colorButton->palette();
  136. palette.setColor(QPalette::Normal, QPalette::ButtonText, color);
  137. m_colorButton->setPalette(palette);
  138. color = QColor(element->contains("background-color") ?
  139. element->value("background-color") : parentElement["background-color"]);
  140. m_backgroundButton->setText(color.name());
  141. palette = m_backgroundButton->palette();
  142. palette.setColor(QPalette::Normal, QPalette::ButtonText, color);
  143. m_backgroundButton->setPalette(palette);
  144. m_fontCombo->setCurrentFont(element->contains("font-family") ?
  145. element->value("font-family") : parentElement["font-family"]);
  146. QString value = element->contains("font-size") ?
  147. element->value("font-size") : parentElement["font-size"];
  148. if (! value.endsWith("pt"))
  149. value = parentElement["font-size"];
  150. m_sizeSpin->setValue(value.left(value.length() - 2).toInt());
  151. value = element->contains("font-weight") ? element->value("font-weight") : parentElement["font-weight"];
  152. m_boldButton->setChecked(value == "bold");
  153. value = element->contains("font-style") ? element->value("font-style") : parentElement["font-style"];
  154. m_italicButton->setChecked(value == "italic");
  155. value = element->contains("text-decoration") ? element->value("text-decoration") : parentElement["text-decoration"];
  156. m_underlineButton->setChecked(value == "underline");
  157. updatePreview();
  158. }
  159. void CSSEdit::propertyChanged()
  160. {
  161. if (! sender())
  162. return;
  163. if (! m_elements.contains(m_currentElement))
  164. return;
  165. Element *element = &m_elements[m_currentElement];
  166. Element parentElement = getParentElement(m_currentElement);
  167. if (sender() == m_fontCombo)
  168. {
  169. QString font = m_fontCombo->currentText();
  170. if (parentElement["font-family"] == font)
  171. element->remove("font-family");
  172. else
  173. element->insert("font-family", font);
  174. }
  175. else if (sender() == m_sizeSpin)
  176. {
  177. QString size = QString::number(m_sizeSpin->value()) + "pt";
  178. if (parentElement["font-size"] == size)
  179. element->remove("font-size");
  180. else
  181. element->insert("font-size", size);
  182. }
  183. else if (sender() == m_boldButton)
  184. {
  185. QString weight = (m_boldButton->isChecked() ? "bold" : "normal");
  186. if (parentElement["font-weight"] == weight)
  187. element->remove("font-weight");
  188. else
  189. element->insert("font-weight", weight);
  190. }
  191. else if(sender() == m_italicButton)
  192. {
  193. QString style = (m_italicButton->isChecked() ? "italic" : "normal");
  194. if (parentElement["font-style"] == style)
  195. element->remove("font-style");
  196. else
  197. element->insert("font-style", style);
  198. }
  199. else if(sender() == m_underlineButton)
  200. {
  201. QString decoration = (m_underlineButton->isChecked() ? "underline" : "none");
  202. if (parentElement["text-decoration"] == decoration)
  203. element->remove("text-decoration");
  204. else
  205. element->insert("text-decoration", decoration);
  206. }
  207. updatePreview();
  208. }
  209. void CSSEdit::colorSelectClicked()
  210. {
  211. QToolButton *colorButton;
  212. QString propertyName;
  213. if (sender() == m_colorButton)
  214. {
  215. colorButton = m_colorButton;
  216. propertyName = "color";
  217. }
  218. else if (sender() == m_backgroundButton)
  219. {
  220. colorButton = m_backgroundButton;
  221. propertyName = "background-color";
  222. }
  223. else
  224. return;
  225. if (! m_elements.contains(m_currentElement))
  226. return;
  227. Element *element = &m_elements[m_currentElement];
  228. Element parentElement = getParentElement(m_currentElement);
  229. QColor color = QColorDialog::getColor(QColor(colorButton->text()), this);
  230. if (color.isValid())
  231. {
  232. colorButton->setText(color.name());
  233. QPalette palette = colorButton->palette();
  234. palette.setColor(QPalette::Normal, QPalette::ButtonText, color);
  235. colorButton->setPalette(palette);
  236. if (parentElement[propertyName] == color.name())
  237. element->remove(propertyName);
  238. else
  239. element->insert(propertyName, color.name());
  240. updatePreview();
  241. }
  242. }
  243. void CSSEdit::updatePreview()
  244. {
  245. QString html = "<style>" + css() + "</style>";
  246. html += "<body>";
  247. for (QHash<QString, Element>::const_iterator i = m_elements.begin(); i != m_elements.end(); ++i)
  248. {
  249. QString alias;
  250. if (m_elementsAliases.contains(i.key()))
  251. alias = m_elementsAliases.value(i.key());
  252. else
  253. alias = i.key();
  254. int pos = i.key().indexOf('.');
  255. if (pos == -1)
  256. html += "<" + i.key() + ">" + alias + "</" + i.key() + "><br>";
  257. else
  258. {
  259. QString parent = i.key().left(pos);
  260. QString class_ = i.key().mid(pos + 1);
  261. html += "<" + parent + " class=\'" + class_ + "\'>" + alias + "</" + parent + "><br>";
  262. }
  263. }
  264. html += "</body>";
  265. m_preview->setHtml(html);
  266. }
  267. void CSSEdit::updateElementCombo()
  268. {
  269. m_elementCombo->clear();
  270. for (QHash<QString, Element>::const_iterator i = m_elements.begin(); i != m_elements.end(); ++i)
  271. {
  272. QString alias;
  273. if (m_elementsAliases.contains(i.key()))
  274. alias = m_elementsAliases.value(i.key());
  275. else
  276. alias = i.key();
  277. m_elementCombo->addItem(alias, i.key());
  278. }
  279. if (m_elements.begin() != m_elements.end())
  280. m_currentElement = m_elements.begin().key();
  281. else
  282. m_currentElement.clear();
  283. }
  284. CSSEdit::Element CSSEdit::getParentElement(const QString &elementName)
  285. {
  286. Element body = m_elements.value("body");
  287. if (elementName == "body")
  288. {
  289. body["color"] = QApplication::palette().color(QPalette::Normal, QPalette::Text).name();
  290. body["background-color"] = QApplication::palette().color(QPalette::Normal, QPalette::Base).name();
  291. body["font-family"] = QApplication::font().family();
  292. body["font-size"] = QString::number(QApplication::font().pointSize()) + "pt";
  293. body["font-weight"] = (QApplication::font().weight() == QFont::Bold) ? "bold" : "normal";
  294. body["font-style"] = (QApplication::font().style() == QFont::StyleItalic) ? "italic" : "normal";
  295. body["text-decoration"] = QApplication::font().underline() ? "underline" : "none";
  296. return body;
  297. }
  298. else
  299. {
  300. if (! body.contains("color"))
  301. body["color"] = QApplication::palette().color(QPalette::Normal, QPalette::Text).name();
  302. if (! body.contains("background-color"))
  303. body["background-color"] = QApplication::palette().color(QPalette::Normal, QPalette::Base).name();
  304. if (! body.contains("font-family"))
  305. body["font-family"] = QApplication::font().family();
  306. if (! body.contains("font-size"))
  307. body["font-size"] = QString::number(QApplication::font().pointSize()) + "pt";
  308. if (! body.contains("font-weight"))
  309. body["font-weight"] = (QApplication::font().weight() == QFont::Bold) ? "bold" : "normal";
  310. if (! body.contains("font-style"))
  311. body["font-style"] = (QApplication::font().style() == QFont::StyleItalic) ? "italic" : "normal";
  312. if (! body.contains("text-decoration"))
  313. body["text-decoration"] = QApplication::font().underline() ? "underline" : "none";
  314. }
  315. QString parentName;
  316. int pos = elementName.indexOf('.');
  317. if (pos != -1)
  318. {
  319. parentName = elementName.left(pos);
  320. if (m_elements.contains(parentName))
  321. {
  322. Element parent = m_elements[parentName];
  323. for (Element::const_iterator i = body.begin(); i != body.end(); ++i)
  324. if (! parent.contains(i.key()))
  325. parent[i.key()] = *i;
  326. return parent;
  327. }
  328. else
  329. return body;
  330. }
  331. return body;
  332. }
  333. }
  334. // vim: tabstop=4 softtabstop=4 shiftwidth=4 expandtab cindent textwidth=120 formatoptions=tc