File indexing completed on 2024-04-28 11:20:56
0001 /* 0002 SPDX-License-Identifier: GPL-2.0-or-later 0003 SPDX-FileCopyrightText: 2020 Sirgienko Nikita <warquark@gmail.com> 0004 */ 0005 0006 #include "horizontalruleentry.h" 0007 0008 #include <QApplication> 0009 #include <QPainter> 0010 #include <QPropertyAnimation> 0011 #include <QJsonObject> 0012 #include <QActionGroup> 0013 0014 #include <KLocalizedString> 0015 0016 #include <jupyterutils.h> 0017 0018 const qreal HorizontalRuleEntry::LineVerticalMargin = 10; 0019 0020 const QString HorizontalRuleEntry::styleNames[] = {i18n("Solid Line Style"), i18n("Dash Line Style"), i18n("Dot Line Style"), i18n("Dash Dot Line Style"), i18n("Dash Dot Dot Line Style")}; 0021 const Qt::PenStyle HorizontalRuleEntry::styles[] = {Qt::SolidLine, Qt::DashLine, Qt::DotLine, Qt::DashDotLine, Qt::DashDotDotLine}; 0022 0023 HorizontalRuleEntry::HorizontalRuleEntry(Worksheet* worksheet) 0024 : WorksheetEntry(worksheet), m_type(LineType::Medium), m_color(QApplication::palette().color(QPalette::Text)), m_entry_zone_offset_x(0), m_width(0), m_style(Qt::SolidLine), 0025 m_menusInitialized(false), m_lineTypeActionGroup(nullptr), m_lineTypeMenu(nullptr), m_lineColorCustom(false), m_lineColorActionGroup(nullptr), m_lineColorMenu(nullptr), 0026 m_lineStyleActionGroup(nullptr), m_lineStyleMenu(nullptr) 0027 { 0028 } 0029 0030 HorizontalRuleEntry::~HorizontalRuleEntry() 0031 { 0032 if (m_menusInitialized) 0033 { 0034 m_lineColorActionGroup->deleteLater(); 0035 m_lineColorMenu->deleteLater(); 0036 m_lineTypeActionGroup->deleteLater(); 0037 m_lineTypeMenu->deleteLater(); 0038 m_lineStyleActionGroup->deleteLater(); 0039 m_lineStyleMenu->deleteLater(); 0040 } 0041 } 0042 0043 int HorizontalRuleEntry::type() const 0044 { 0045 return Type; 0046 } 0047 0048 void HorizontalRuleEntry::setLineType(HorizontalRuleEntry::LineType type) 0049 { 0050 m_type = type; 0051 0052 setSize(QSizeF(m_width, lineWidth(m_type) + 2*LineVerticalMargin)); 0053 } 0054 0055 int HorizontalRuleEntry::lineWidth(HorizontalRuleEntry::LineType type) 0056 { 0057 return type == LineType::Thick ? 4 : ((int)type) + 1; 0058 } 0059 0060 void HorizontalRuleEntry::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) 0061 { 0062 Q_UNUSED(option); 0063 Q_UNUSED(widget); 0064 0065 painter->setPen(QPen(m_color, lineWidth(m_type), m_style)); 0066 0067 const qreal margin = worksheet()->isPrinting() ? 0 : RightMargin; 0068 0069 painter->drawLine(m_entry_zone_offset_x, LineVerticalMargin, m_width - margin, LineVerticalMargin); 0070 } 0071 0072 bool HorizontalRuleEntry::isEmpty() 0073 { 0074 return true; 0075 } 0076 0077 bool HorizontalRuleEntry::acceptRichText() 0078 { 0079 return false; 0080 } 0081 0082 void HorizontalRuleEntry::setContent(const QString&) 0083 { 0084 } 0085 0086 void HorizontalRuleEntry::setContent(const QDomElement& content, const KZip& archive) 0087 { 0088 Q_UNUSED(archive); 0089 0090 m_type = (LineType)(content.attribute(QLatin1String("thickness"), QString::number((int)LineType::Medium)).toInt()); 0091 m_style = (Qt::PenStyle)(content.attribute(QLatin1String("style"), QString::number((int)Qt::SolidLine)).toInt()); 0092 0093 QDomElement backgroundElem = content.firstChildElement(QLatin1String("lineColor")); 0094 if (!backgroundElem.isNull()) 0095 { 0096 m_color.setRed(backgroundElem.attribute(QLatin1String("red")).toInt()); 0097 m_color.setGreen(backgroundElem.attribute(QLatin1String("green")).toInt()); 0098 m_color.setBlue(backgroundElem.attribute(QLatin1String("blue")).toInt()); 0099 m_lineColorCustom = true; 0100 } 0101 } 0102 0103 void HorizontalRuleEntry::setContentFromJupyter(const QJsonObject& cell) 0104 { 0105 QJsonObject cantorMetadata = Cantor::JupyterUtils::getCantorMetadata(cell); 0106 QJsonValue typeValue = cantorMetadata.value(QLatin1String("type")); 0107 if (typeValue.isDouble()) 0108 setLineType(static_cast<LineType>(static_cast<int>(typeValue.toDouble()))); 0109 0110 QJsonValue styleValue = cantorMetadata.value(QLatin1String("style")); 0111 if (styleValue.isDouble()) 0112 m_style = static_cast<Qt::PenStyle>(static_cast<int>(styleValue.toDouble())); 0113 0114 QJsonValue colorValue = cantorMetadata.value(QLatin1String("lineColor")); 0115 if (colorValue.isObject()) 0116 { 0117 m_color.setRed(colorValue.toObject().value(QLatin1String("red")).toInt()); 0118 m_color.setGreen(colorValue.toObject().value(QLatin1String("green")).toInt()); 0119 m_color.setBlue(colorValue.toObject().value(QLatin1String("blue")).toInt()); 0120 m_lineColorCustom = true; 0121 } 0122 0123 setJupyterMetadata(Cantor::JupyterUtils::getMetadata(cell)); 0124 } 0125 0126 QJsonValue HorizontalRuleEntry::toJupyterJson() 0127 { 0128 QJsonObject entry; 0129 0130 entry.insert(QLatin1String("cell_type"), QLatin1String("markdown")); 0131 QJsonObject metadata(jupyterMetadata()); 0132 0133 QJsonObject cantor; 0134 cantor.insert(QLatin1String("type"), m_type); 0135 cantor.insert(QLatin1String("style"), m_style); 0136 0137 if (m_lineColorCustom) 0138 { 0139 QJsonObject color; 0140 color.insert(QLatin1String("red"), m_color.red()); 0141 color.insert(QLatin1String("green"), m_color.green()); 0142 color.insert(QLatin1String("blue"), m_color.blue()); 0143 cantor.insert(QLatin1String("lineColor"), color); 0144 } 0145 0146 metadata.insert(Cantor::JupyterUtils::cantorMetadataKey, cantor); 0147 0148 entry.insert(Cantor::JupyterUtils::metadataKey, metadata); 0149 0150 Cantor::JupyterUtils::setSource(entry, QLatin1String("----")); 0151 return entry; 0152 } 0153 0154 0155 QDomElement HorizontalRuleEntry::toXml(QDomDocument& doc, KZip* archive) 0156 { 0157 Q_UNUSED(archive); 0158 0159 QDomElement el = doc.createElement(QLatin1String("HorizontalRule")); 0160 el.setAttribute(QLatin1String("thickness"), (int)m_type); 0161 el.setAttribute(QLatin1String("style"), (int)m_style); 0162 0163 if (m_lineColorCustom) 0164 { 0165 QColor backgroundColor = m_color; 0166 QDomElement colorElem = doc.createElement( QLatin1String("lineColor") ); 0167 colorElem.setAttribute(QLatin1String("red"), QString::number(backgroundColor.red())); 0168 colorElem.setAttribute(QLatin1String("green"), QString::number(backgroundColor.green())); 0169 colorElem.setAttribute(QLatin1String("blue"), QString::number(backgroundColor.blue())); 0170 el.appendChild(colorElem); 0171 } 0172 0173 return el; 0174 } 0175 0176 QString HorizontalRuleEntry::toPlain(const QString&, const QString&, const QString&){ 0177 return QString(); 0178 } 0179 0180 void HorizontalRuleEntry::layOutForWidth(qreal entry_zone_x, qreal w, bool force) 0181 { 0182 Q_UNUSED(force); 0183 0184 m_entry_zone_offset_x = entry_zone_x; 0185 m_width = w; 0186 0187 setSize(QSizeF(w, lineWidth(m_type) + 2*LineVerticalMargin)); 0188 } 0189 0190 bool HorizontalRuleEntry::evaluate(EvaluationOption evalOp) 0191 { 0192 evaluateNext(evalOp); 0193 return true; 0194 } 0195 0196 void HorizontalRuleEntry::updateEntry() 0197 { 0198 } 0199 0200 bool HorizontalRuleEntry::wantToEvaluate() 0201 { 0202 return false; 0203 } 0204 0205 void HorizontalRuleEntry::changeSize(QSizeF s) 0206 { 0207 if (!worksheet()->animationsEnabled()) { 0208 setSize(s); 0209 worksheet()->updateEntrySize(this); 0210 return; 0211 } 0212 if (aboutToBeRemoved()) 0213 return; 0214 0215 if (animationActive()) 0216 endAnimation(); 0217 0218 QPropertyAnimation* sizeAn = sizeChangeAnimation(s); 0219 0220 sizeAn->setEasingCurve(QEasingCurve::InOutQuad); 0221 sizeAn->start(QAbstractAnimation::DeleteWhenStopped); 0222 } 0223 0224 void HorizontalRuleEntry::populateMenu(QMenu* menu, QPointF pos) 0225 { 0226 if (!m_menusInitialized) 0227 { 0228 initMenus(); 0229 m_menusInitialized = true; 0230 } 0231 0232 menu->addMenu(m_lineTypeMenu); 0233 menu->addMenu(m_lineColorMenu); 0234 menu->addMenu(m_lineStyleMenu); 0235 WorksheetEntry::populateMenu(menu, pos); 0236 } 0237 0238 void HorizontalRuleEntry::lineTypeChanged(QAction* action) 0239 { 0240 int index = m_lineTypeActionGroup->actions().indexOf(action); 0241 setLineType((LineType)(index % LineType::Count)); 0242 } 0243 0244 bool HorizontalRuleEntry::isConvertableToHorizontalRuleEntry(const QJsonObject& cell) 0245 { 0246 if (!Cantor::JupyterUtils::isMarkdownCell(cell)) 0247 return false; 0248 0249 const QString& trimmedSource = Cantor::JupyterUtils::getSource(cell).trimmed(); 0250 0251 int sourceLength = trimmedSource.length(); 0252 if (sourceLength < 3) 0253 return false; 0254 0255 int hyphensCount = trimmedSource.count(QLatin1Char('-')); 0256 int asteriksCount = trimmedSource.count(QLatin1Char('*')); 0257 int underscoreCount = trimmedSource.count(QLatin1Char('_')); 0258 0259 return sourceLength == hyphensCount || sourceLength == asteriksCount || sourceLength == underscoreCount; 0260 } 0261 0262 void HorizontalRuleEntry::lineColorChanged(QAction* action) { 0263 int index = m_lineColorActionGroup->actions().indexOf(action); 0264 if (index == -1 || index>=colorsCount) 0265 index = 0; 0266 0267 if (index == 0) 0268 { 0269 m_color = QApplication::palette().color(QPalette::Text); 0270 m_lineColorCustom = false; 0271 } 0272 else 0273 { 0274 m_color = colors[index-1]; 0275 m_lineColorCustom = true; 0276 } 0277 update(); 0278 } 0279 0280 void HorizontalRuleEntry::lineStyleChanged(QAction* action) 0281 { 0282 unsigned int index = static_cast<unsigned int>(m_lineStyleActionGroup->actions().indexOf(action)); 0283 if (index > 0 && index < styleCount) 0284 { 0285 m_style = styles[index]; 0286 update(); 0287 } 0288 } 0289 0290 0291 void HorizontalRuleEntry::initMenus() 0292 { 0293 m_lineTypeActionGroup = new QActionGroup(this); 0294 m_lineTypeActionGroup->setExclusive(true); 0295 connect(m_lineTypeActionGroup, &QActionGroup::triggered, this, &HorizontalRuleEntry::lineTypeChanged); 0296 0297 m_lineTypeMenu = new QMenu(i18n("Line Thickness")); 0298 0299 QAction* action = new QAction(i18n("Thin"), m_lineTypeActionGroup); 0300 action->setCheckable(true); 0301 m_lineTypeMenu->addAction(action); 0302 0303 action = new QAction(i18n("Medium"), m_lineTypeActionGroup); 0304 action->setCheckable(true); 0305 m_lineTypeMenu->addAction(action); 0306 0307 action = new QAction(i18n("Thick"), m_lineTypeActionGroup); 0308 action->setCheckable(true); 0309 m_lineTypeMenu->addAction(action); 0310 0311 // Set default menu value 0312 m_lineTypeActionGroup->actions()[(int)m_type]->setChecked(true); 0313 0314 0315 0316 m_lineColorActionGroup = new QActionGroup(this); 0317 m_lineColorActionGroup->setExclusive(true); 0318 connect(m_lineColorActionGroup, &QActionGroup::triggered, this, &HorizontalRuleEntry::lineColorChanged); 0319 0320 m_lineColorMenu = new QMenu(i18n("Line Color")); 0321 m_lineColorMenu->setIcon(QIcon::fromTheme(QLatin1String("format-fill-color"))); 0322 0323 QPixmap pix(16,16); 0324 QPainter p(&pix); 0325 0326 // Create default action 0327 p.fillRect(pix.rect(), QApplication::palette().color(QPalette::Text)); 0328 action = new QAction(QIcon(pix), i18n("Default"), m_lineColorActionGroup); 0329 action->setCheckable(true); 0330 m_lineColorMenu->addAction(action); 0331 if (!m_lineColorCustom) 0332 action->setChecked(true); 0333 0334 0335 for (int i=0; i<colorsCount; ++i) { 0336 p.fillRect(pix.rect(), colors[i]); 0337 action = new QAction(QIcon(pix), colorNames[i], m_lineColorActionGroup); 0338 action->setCheckable(true); 0339 m_lineColorMenu->addAction(action); 0340 0341 if (m_lineColorCustom && m_color == colors[i]) 0342 action->setChecked(true); 0343 } 0344 0345 0346 0347 m_lineStyleActionGroup = new QActionGroup(this); 0348 m_lineStyleActionGroup->setExclusive(true); 0349 connect(m_lineStyleActionGroup, &QActionGroup::triggered, this, &HorizontalRuleEntry::lineStyleChanged); 0350 0351 m_lineStyleMenu = new QMenu(i18n("Line Style")); 0352 0353 for (unsigned int i = 0; i < styleCount; i++) 0354 { 0355 action = new QAction(styleNames[i], m_lineStyleActionGroup); 0356 action->setCheckable(true); 0357 m_lineStyleMenu->addAction(action); 0358 if (styles[i] == m_style) 0359 action->setChecked(true); 0360 } 0361 }