File indexing completed on 2025-09-14 03:43:30
0001 /* 0002 File : LabelWidget.cc 0003 Project : LabPlot 0004 Description : label settings widget 0005 -------------------------------------------------------------------- 0006 SPDX-FileCopyrightText: 2008-2022 Alexander Semke <alexander.semke@web.de> 0007 SPDX-FileCopyrightText: 2012-2022 Stefan Gerlach <stefan.gerlach@uni-konstanz.de> 0008 SPDX-License-Identifier: GPL-2.0-or-later 0009 */ 0010 0011 #include "LabelWidget.h" 0012 #include "backend/core/Settings.h" 0013 #include "backend/worksheet/Background.h" 0014 #include "backend/worksheet/Worksheet.h" 0015 #include "backend/worksheet/plots/PlotArea.h" 0016 #include "backend/worksheet/plots/cartesian/Axis.h" 0017 #include "backend/worksheet/plots/cartesian/CartesianPlot.h" 0018 #include "backend/worksheet/plots/cartesian/CartesianPlotLegend.h" 0019 #include "kdefrontend/GuiTools.h" 0020 #include "kdefrontend/dockwidgets/BaseDock.h" 0021 #include "tools/TeXRenderer.h" 0022 0023 #include <KCharSelect> 0024 #include <KLocalizedString> 0025 #ifdef HAVE_KF5_SYNTAX_HIGHLIGHTING 0026 #include <KSyntaxHighlighting/Definition> 0027 #include <KSyntaxHighlighting/SyntaxHighlighter> 0028 #include <KSyntaxHighlighting/Theme> 0029 #endif 0030 #include <KMessageWidget> 0031 0032 #include <QFile> 0033 #include <QMenu> 0034 #include <QSettings> 0035 #include <QSplitter> 0036 #include <QStandardItemModel> 0037 #include <QTextDocumentFragment> 0038 #include <QWidgetAction> 0039 0040 #include <gsl/gsl_const_cgs.h> 0041 0042 /*! 0043 * Setting label property without changing the content. This is needed, 0044 * because the text is html formatted and therefore setting properties 0045 * is not that easy 0046 */ 0047 #define SETLABELTEXTPROPERTY(TextEditFunction, TextEditArgument) \ 0048 auto cursor = ui.teLabel->textCursor(); \ 0049 int cursorAnchor = cursor.anchor(), cursorPos = cursor.position(); \ 0050 /* move position with right allows only positive numbers (from left to right) */ \ 0051 if (cursorAnchor > cursorPos) \ 0052 qSwap(cursorAnchor, cursorPos); \ 0053 bool cursorHasSelection = cursor.hasSelection(); \ 0054 if (!cursorHasSelection) \ 0055 ui.teLabel->selectAll(); \ 0056 \ 0057 ui.teLabel->TextEditFunction(TextEditArgument); \ 0058 QTextEdit te; \ 0059 for (auto& label : m_labelsList) { \ 0060 TextLabel::TextWrapper w = label->text(); \ 0061 te.setText(w.text); \ 0062 if (!cursorHasSelection) \ 0063 te.selectAll(); \ 0064 else { \ 0065 /* Set cursor as it is in the ui.teLabel*/ \ 0066 auto c = te.textCursor(); \ 0067 c.setPosition(cursorAnchor); \ 0068 c.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor, cursorPos - cursorAnchor); \ 0069 te.setTextCursor(c); \ 0070 } \ 0071 te.TextEditFunction(TextEditArgument); \ 0072 w.text = te.toHtml(); \ 0073 label->setText(w); \ 0074 } \ 0075 \ 0076 if (!cursorHasSelection) { \ 0077 cursor.clearSelection(); \ 0078 ui.teLabel->setTextCursor(cursor); \ 0079 } 0080 0081 /*! 0082 \class LabelWidget 0083 \brief Widget for editing the properties of a TextLabel object, mostly used in an appropriate dock widget. 0084 0085 In order the properties of the label to be shown, \c loadConfig() has to be called with the corresponding KConfigGroup 0086 (settings for a label in *Plot, Axis etc. or for an independent label on the worksheet). 0087 0088 \ingroup kdefrontend 0089 */ 0090 LabelWidget::LabelWidget(QWidget* parent) 0091 : BaseDock(parent) 0092 , m_dateTimeMenu(new QMenu(this)) { 0093 ui.setupUi(this); 0094 setBaseWidgets(ui.leName, ui.teComment); 0095 setVisibilityWidgets(ui.chbVisible); 0096 0097 // set the minimum size of the text edit widget to one row of a QLabel 0098 ui.teLabel->setMinimumHeight(ui.lName->height()); 0099 0100 // adjust the layout margins 0101 if (auto* l = dynamic_cast<QGridLayout*>(layout())) { 0102 l->setContentsMargins(2, 2, 2, 2); 0103 l->setHorizontalSpacing(2); 0104 l->setVerticalSpacing(2); 0105 } 0106 0107 const KConfigGroup group = Settings::group(QStringLiteral("Settings_General")); 0108 m_units = (BaseDock::Units)group.readEntry("Units", (int)BaseDock::Units::Metric); 0109 if (m_units == BaseDock::Units::Imperial) 0110 m_worksheetUnit = Worksheet::Unit::Inch; 0111 0112 m_dateTimeMenu->setSeparatorsCollapsible(false); // we don't want the first separator to be removed 0113 0114 QString msg = i18n("Use logical instead of absolute coordinates to specify the position on the plot"); 0115 ui.chbBindLogicalPos->setToolTip(msg); 0116 0117 ui.sbBorderWidth->setMinimum(0); 0118 0119 // Icons 0120 ui.tbFontBold->setIcon(QIcon::fromTheme(QLatin1String("format-text-bold"))); 0121 ui.tbFontItalic->setIcon(QIcon::fromTheme(QLatin1String("format-text-italic"))); 0122 ui.tbFontUnderline->setIcon(QIcon::fromTheme(QLatin1String("format-text-underline"))); 0123 ui.tbFontStrikeOut->setIcon(QIcon::fromTheme(QLatin1String("format-text-strikethrough"))); 0124 ui.tbFontSuperScript->setIcon(QIcon::fromTheme(QLatin1String("format-text-superscript"))); 0125 ui.tbFontSubScript->setIcon(QIcon::fromTheme(QLatin1String("format-text-subscript"))); 0126 ui.tbSymbols->setIcon(QIcon::fromTheme(QLatin1String("labplot-format-text-symbol"))); 0127 ui.tbDateTime->setIcon(QIcon::fromTheme(QLatin1String("chronometer"))); 0128 0129 ui.tbFontBold->setToolTip(i18n("Bold")); 0130 ui.tbFontItalic->setToolTip(i18n("Italic")); 0131 ui.tbFontUnderline->setToolTip(i18n("Underline")); 0132 ui.tbFontStrikeOut->setToolTip(i18n("Strike Out")); 0133 ui.tbFontSuperScript->setToolTip(i18n("Super Script")); 0134 ui.tbFontSubScript->setToolTip(i18n("Sub-Script")); 0135 ui.tbSymbols->setToolTip(i18n("Insert Symbol")); 0136 ui.tbDateTime->setToolTip(i18n("Insert Date/Time")); 0137 0138 // Positioning and alignment 0139 ui.cbPositionX->addItem(i18n("Left")); 0140 ui.cbPositionX->addItem(i18n("Center")); 0141 ui.cbPositionX->addItem(i18n("Right")); 0142 ui.cbPositionX->addItem(i18n("Relative to plot")); 0143 0144 ui.cbPositionY->addItem(i18n("Top")); 0145 ui.cbPositionY->addItem(i18n("Center")); 0146 ui.cbPositionY->addItem(i18n("Bottom")); 0147 ui.cbPositionY->addItem(i18n("Relative to plot")); 0148 0149 QString suffix; 0150 if (m_units == BaseDock::Units::Metric) 0151 suffix = QLatin1String(" cm"); 0152 else 0153 suffix = QLatin1String(" in"); 0154 0155 ui.sbPositionX->setSuffix(suffix); 0156 ui.sbPositionY->setSuffix(suffix); 0157 0158 ui.cbHorizontalAlignment->addItem(i18n("Left")); 0159 ui.cbHorizontalAlignment->addItem(i18n("Center")); 0160 ui.cbHorizontalAlignment->addItem(i18n("Right")); 0161 0162 ui.cbVerticalAlignment->addItem(i18n("Top")); 0163 ui.cbVerticalAlignment->addItem(i18n("Center")); 0164 ui.cbVerticalAlignment->addItem(i18n("Bottom")); 0165 0166 ui.cbBorderShape->addItem(i18n("No Border")); 0167 ui.cbBorderShape->addItem(i18n("Rectangle")); 0168 ui.cbBorderShape->addItem(i18n("Ellipse")); 0169 ui.cbBorderShape->addItem(i18n("Round sided rectangle")); 0170 ui.cbBorderShape->addItem(i18n("Round corner rectangle")); 0171 ui.cbBorderShape->addItem(i18n("Inwards round corner rectangle")); 0172 ui.cbBorderShape->addItem(i18n("Dented border rectangle")); 0173 ui.cbBorderShape->addItem(i18n("Cuboid")); 0174 ui.cbBorderShape->addItem(i18n("Up Pointing rectangle")); 0175 ui.cbBorderShape->addItem(i18n("Down Pointing rectangle")); 0176 ui.cbBorderShape->addItem(i18n("Left Pointing rectangle")); 0177 ui.cbBorderShape->addItem(i18n("Right Pointing rectangle")); 0178 0179 ui.cbBorderStyle->addItem(i18n("No line")); 0180 ui.cbBorderStyle->addItem(i18n("Solid line")); 0181 ui.cbBorderStyle->addItem(i18n("Dash line")); 0182 ui.cbBorderStyle->addItem(i18n("Dot line")); 0183 ui.cbBorderStyle->addItem(i18n("Dash dot line")); 0184 ui.cbBorderStyle->addItem(i18n("Dash dot dot line")); 0185 0186 ui.kcbBackgroundColor->setAlphaChannelEnabled(true); 0187 ui.kcbBackgroundColor->setColor(QColor(0, 0, 0, 0)); // transparent 0188 ui.kcbFontColor->setAlphaChannelEnabled(true); 0189 ui.kcbFontColor->setColor(QColor(255, 255, 255, 255)); // black 0190 ui.kcbBorderColor->setAlphaChannelEnabled(true); 0191 ui.kcbBorderColor->setColor(QColor(255, 255, 255, 255)); // black 0192 0193 // Text mode 0194 ui.cbMode->addItem(QIcon::fromTheme(QLatin1String("text-x-plain")), i18n("Text")); 0195 ui.cbMode->addItem(QIcon::fromTheme(QLatin1String("text-x-tex")), i18n("LaTeX")); 0196 #ifdef HAVE_DISCOUNT 0197 ui.cbMode->addItem(QIcon::fromTheme(QLatin1String("text-x-markdown")), i18n("Markdown")); 0198 #endif 0199 0200 msg = i18n( 0201 "Text setting mode:" 0202 "<ul>" 0203 "<li>Text - text setting using rich-text formatting</li>" 0204 "<li>LaTeX - text setting using LaTeX, installation of LaTeX required</li>" 0205 #ifdef HAVE_DISCOUNT 0206 "<li>Markdown - text setting using Markdown markup language</li>" 0207 #endif 0208 "</ul>"); 0209 ui.cbMode->setToolTip(msg); 0210 0211 // check whether LaTeX is available and deactivate the item in the combobox, if not. 0212 // in case LaTeX was used to generate the text label in the stored project 0213 // and no LaTeX is available on the target system, the disabled LaTeX item is selected 0214 // in the combobox in load() and the user still can switch to the non-latex mode. 0215 m_teXEnabled = TeXRenderer::enabled(); 0216 if (!m_teXEnabled) { 0217 const auto* model = qobject_cast<QStandardItemModel*>(ui.cbMode->model()); 0218 model->item(1)->setEnabled(false); 0219 } 0220 0221 #ifdef HAVE_KF5_SYNTAX_HIGHLIGHTING 0222 m_highlighter = new KSyntaxHighlighting::SyntaxHighlighter(ui.teLabel->document()); 0223 m_highlighter->setTheme(GuiTools::isDarkMode() ? m_repository.defaultTheme(KSyntaxHighlighting::Repository::DarkTheme) 0224 : m_repository.defaultTheme(KSyntaxHighlighting::Repository::LightTheme)); 0225 #endif 0226 0227 m_messageWidget = new KMessageWidget(this); 0228 m_messageWidget->setMessageType(KMessageWidget::Error); 0229 m_messageWidget->setWordWrap(true); 0230 auto* gridLayout = qobject_cast<QGridLayout*>(layout()); 0231 gridLayout->addWidget(m_messageWidget, 2, 3); 0232 m_messageWidget->hide(); // will be shown later once there is a latex render result 0233 0234 // SLOTS 0235 0236 // text properties 0237 connect(ui.cbMode, QOverload<int>::of(&KComboBox::currentIndexChanged), this, &LabelWidget::modeChanged); 0238 connect(ui.teLabel, &ResizableTextEdit::textChanged, this, &LabelWidget::textChanged); 0239 connect(ui.teLabel, &ResizableTextEdit::currentCharFormatChanged, this, &LabelWidget::charFormatChanged); 0240 connect(ui.kcbFontColor, &KColorButton::changed, this, &LabelWidget::fontColorChanged); 0241 connect(ui.kcbBackgroundColor, &KColorButton::changed, this, &LabelWidget::backgroundColorChanged); 0242 connect(ui.tbFontBold, &QToolButton::clicked, this, &LabelWidget::fontBoldChanged); 0243 connect(ui.tbFontItalic, &QToolButton::clicked, this, &LabelWidget::fontItalicChanged); 0244 connect(ui.tbFontUnderline, &QToolButton::clicked, this, &LabelWidget::fontUnderlineChanged); 0245 connect(ui.tbFontStrikeOut, &QToolButton::clicked, this, &LabelWidget::fontStrikeOutChanged); 0246 connect(ui.tbFontSuperScript, &QToolButton::clicked, this, &LabelWidget::fontSuperScriptChanged); 0247 connect(ui.tbFontSubScript, &QToolButton::clicked, this, &LabelWidget::fontSubScriptChanged); 0248 connect(ui.tbSymbols, &QToolButton::clicked, this, &LabelWidget::charMenu); 0249 connect(ui.tbDateTime, &QToolButton::clicked, this, &LabelWidget::dateTimeMenu); 0250 connect(m_dateTimeMenu, &QMenu::triggered, this, &LabelWidget::insertDateTime); 0251 connect(ui.kfontRequester, &KFontRequester::fontSelected, this, &LabelWidget::fontChanged); 0252 connect(ui.kfontRequesterTeX, &KFontRequester::fontSelected, this, &LabelWidget::teXFontChanged); 0253 connect(ui.sbFontSize, QOverload<int>::of(&QSpinBox::valueChanged), this, &LabelWidget::fontSizeChanged); 0254 0255 // geometry 0256 connect(ui.cbPositionX, QOverload<int>::of(&KComboBox::currentIndexChanged), this, &LabelWidget::positionXChanged); 0257 connect(ui.cbPositionY, QOverload<int>::of(&KComboBox::currentIndexChanged), this, &LabelWidget::positionYChanged); 0258 connect(ui.sbPositionX, QOverload<double>::of(&NumberSpinBox::valueChanged), this, &LabelWidget::customPositionXChanged); 0259 connect(ui.sbPositionY, QOverload<double>::of(&NumberSpinBox::valueChanged), this, &LabelWidget::customPositionYChanged); 0260 connect(ui.cbHorizontalAlignment, QOverload<int>::of(&KComboBox::currentIndexChanged), this, &LabelWidget::horizontalAlignmentChanged); 0261 connect(ui.cbVerticalAlignment, QOverload<int>::of(&KComboBox::currentIndexChanged), this, &LabelWidget::verticalAlignmentChanged); 0262 0263 connect(ui.sbPositionXLogical, QOverload<double>::of(&NumberSpinBox::valueChanged), this, &LabelWidget::positionXLogicalChanged); 0264 connect(ui.dtePositionXLogical, &UTCDateTimeEdit::mSecsSinceEpochUTCChanged, this, &LabelWidget::positionXLogicalDateTimeChanged); 0265 connect(ui.sbPositionYLogical, QOverload<double>::of(&NumberSpinBox::valueChanged), this, &LabelWidget::positionYLogicalChanged); 0266 // TODO?: connect(ui.dtePositionYLogical, &UTCDateTimeEdit::mSecsSinceEpochUTCChanged, this, &LabelWidget::positionYLogicalDateTimeChanged); 0267 connect(ui.sbRotation, QOverload<int>::of(&QSpinBox::valueChanged), this, &LabelWidget::rotationChanged); 0268 connect(ui.sbOffsetX, QOverload<double>::of(&NumberSpinBox::valueChanged), this, &LabelWidget::offsetXChanged); 0269 connect(ui.sbOffsetY, QOverload<double>::of(&NumberSpinBox::valueChanged), this, &LabelWidget::offsetYChanged); 0270 0271 connect(ui.chbLock, &QCheckBox::clicked, this, &LabelWidget::lockChanged); 0272 connect(ui.chbBindLogicalPos, &QCheckBox::clicked, this, &LabelWidget::bindingChanged); 0273 connect(ui.chbShowPlaceholderText, &QCheckBox::toggled, this, &LabelWidget::showPlaceholderTextChanged); 0274 0275 // Border 0276 connect(ui.cbBorderShape, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &LabelWidget::borderShapeChanged); 0277 connect(ui.cbBorderStyle, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &LabelWidget::borderStyleChanged); 0278 connect(ui.kcbBorderColor, &KColorButton::changed, this, &LabelWidget::borderColorChanged); 0279 connect(ui.sbBorderWidth, QOverload<double>::of(&NumberSpinBox::valueChanged), this, &LabelWidget::borderWidthChanged); 0280 connect(ui.sbBorderOpacity, QOverload<int>::of(&QSpinBox::valueChanged), this, &LabelWidget::borderOpacityChanged); 0281 0282 // TODO: https://bugreports.qt.io/browse/QTBUG-25420 0283 ui.tbFontUnderline->hide(); 0284 ui.tbFontStrikeOut->hide(); 0285 } 0286 0287 void LabelWidget::setLabels(QList<TextLabel*> labels) { 0288 m_labelsList = labels; 0289 m_axesList.clear(); 0290 m_label = labels.first(); 0291 setAspects(labels); 0292 0293 ui.lOffsetX->hide(); 0294 ui.lOffsetY->hide(); 0295 0296 ui.sbOffsetX->hide(); 0297 ui.sbOffsetY->hide(); 0298 0299 // show the text fields for name and comment if the label is not hidden (i.e. not a plot title, etc.) 0300 bool visible = !m_label->hidden(); 0301 ui.lName->setVisible(visible); 0302 ui.leName->setVisible(visible); 0303 ui.lComment->setVisible(visible); 0304 ui.teComment->setVisible(visible); 0305 0306 this->load(); 0307 initConnections(); 0308 updateBackground(); 0309 updateLocale(); 0310 0311 // hide the option "Visible" if the label is child of a InfoElement, 0312 // the label is what the user identifies with the info element itself 0313 visible = (m_label->parentAspect()->type() != AspectType::InfoElement); 0314 ui.chbVisible->setVisible(visible); 0315 0316 // hide the option "Lock" if the label is child of an axis, the label cannot be freely moved in this case 0317 visible = (m_label->parentAspect()->type() != AspectType::Axis); 0318 ui.chbLock->setVisible(visible); 0319 0320 // resize the widget to take the minimal height 0321 layout()->activate(); 0322 const auto s = QSize(this->width(), 0).expandedTo(minimumSize()); 0323 if (s.height() > 0) 0324 resize(s); 0325 } 0326 0327 void LabelWidget::setAxes(QList<Axis*> axes) { 0328 m_labelsList.clear(); 0329 for (const auto* axis : axes) { 0330 DEBUG(Q_FUNC_INFO << ", axis TITLE = " << axis->title()) 0331 m_labelsList.append(axis->title()); 0332 connect(axis, &Axis::titleOffsetXChanged, this, &LabelWidget::labelOffsetXChanged); 0333 connect(axis, &Axis::titleOffsetYChanged, this, &LabelWidget::labelOffsetYChanged); 0334 connect(axis->title(), &TextLabel::rotationAngleChanged, this, &LabelWidget::labelRotationAngleChanged); 0335 } 0336 0337 m_axesList = axes; 0338 m_label = m_labelsList.first(); 0339 setAspects(m_labelsList); 0340 0341 ui.lName->hide(); 0342 ui.leName->hide(); 0343 ui.lComment->hide(); 0344 ui.teComment->hide(); 0345 0346 this->load(); 0347 initConnections(); 0348 updateBackground(); 0349 updateLocale(); 0350 0351 // resize the widget to take the minimal height 0352 layout()->activate(); 0353 const auto s = QSize(this->width(), 0).expandedTo(minimumSize()); 0354 if (s.height() > 0) 0355 resize(s); 0356 } 0357 0358 /*! 0359 * this function keeps the background color of the TextEdit in LabelWidget in sync with 0360 * the background color of the parent aspect. This is to avoid the situations where the 0361 * text wouldn't be readable anymore if the foreground color is close or equal to the 0362 * background color of TextEdit - e.g., a label with white foreground color on a dark worksheet 0363 * and with white background color in TextEdit (desktop default color). 0364 * 0365 * Called if the background color of the parent aspect has changed. 0366 */ 0367 void LabelWidget::updateBackground() const { 0368 // if latex or markdown mode is used, use the default palette from the desktop theme 0369 // since we have additional highlighting for latex and markdown and we don't want it to 0370 // collide with the modified background color of QTextEdit. Modify it only for rich-text. 0371 const auto mode = static_cast<TextLabel::Mode>(ui.cbMode->currentIndex()); 0372 if (mode != TextLabel::Mode::Text) { 0373 ui.teLabel->setPalette(QPalette()); 0374 return; 0375 } 0376 0377 QColor color(Qt::white); 0378 const auto type = m_label->parentAspect()->type(); 0379 if (type == AspectType::Worksheet) 0380 color = static_cast<const Worksheet*>(m_label->parentAspect())->background()->firstColor(); 0381 else if (type == AspectType::CartesianPlot) 0382 color = static_cast<CartesianPlot*>(m_label->parentAspect())->plotArea()->background()->firstColor(); 0383 else if (type == AspectType::CartesianPlotLegend) 0384 color = static_cast<const CartesianPlotLegend*>(m_label->parentAspect())->background()->firstColor(); 0385 else if (type == AspectType::InfoElement || type == AspectType::Axis) 0386 color = static_cast<CartesianPlot*>(m_label->parentAspect()->parentAspect())->plotArea()->background()->firstColor(); 0387 else 0388 DEBUG(Q_FUNC_INFO << ", Not handled type:" << static_cast<int>(type)); 0389 0390 auto p = ui.teLabel->palette(); 0391 // QDEBUG(Q_FUNC_INFO << ", color = " << color) 0392 p.setColor(QPalette::Base, color); 0393 ui.teLabel->setPalette(p); 0394 } 0395 0396 void LabelWidget::initConnections() { 0397 while (!m_connections.isEmpty()) 0398 disconnect(m_connections.takeFirst()); 0399 m_connections << connect(m_label, &TextLabel::textWrapperChanged, this, &LabelWidget::labelTextWrapperChanged); 0400 m_connections << connect(m_label, &TextLabel::teXImageUpdated, this, &LabelWidget::labelTeXImageUpdated); 0401 m_connections << connect(m_label, &TextLabel::teXFontChanged, this, &LabelWidget::labelTeXFontChanged); 0402 m_connections << connect(m_label, &TextLabel::fontColorChanged, this, &LabelWidget::labelFontColorChanged); 0403 m_connections << connect(m_label, &TextLabel::backgroundColorChanged, this, &LabelWidget::labelBackgroundColorChanged); 0404 m_connections << connect(m_label, &TextLabel::positionChanged, this, &LabelWidget::labelPositionChanged); 0405 0406 m_connections << connect(m_label, &TextLabel::positionLogicalChanged, this, &LabelWidget::labelPositionLogicalChanged); 0407 m_connections << connect(m_label, &TextLabel::coordinateBindingEnabledChanged, this, &LabelWidget::labelCoordinateBindingEnabledChanged); 0408 m_connections << connect(m_label, &TextLabel::horizontalAlignmentChanged, this, &LabelWidget::labelHorizontalAlignmentChanged); 0409 m_connections << connect(m_label, &TextLabel::verticalAlignmentChanged, this, &LabelWidget::labelVerticalAlignmentChanged); 0410 m_connections << connect(m_label, &TextLabel::rotationAngleChanged, this, &LabelWidget::labelRotationAngleChanged); 0411 m_connections << connect(m_label, &TextLabel::borderShapeChanged, this, &LabelWidget::labelBorderShapeChanged); 0412 m_connections << connect(m_label, &TextLabel::borderPenChanged, this, &LabelWidget::labelBorderPenChanged); 0413 m_connections << connect(m_label, &TextLabel::borderOpacityChanged, this, &LabelWidget::labelBorderOpacityChanged); 0414 m_connections << connect(m_label, &TextLabel::lockChanged, this, &LabelWidget::labelLockChanged); 0415 0416 if (!m_label->parentAspect()) { 0417 QDEBUG(Q_FUNC_INFO << ", LABEL " << m_label << " HAS NO PARENT!") 0418 return; 0419 } 0420 AspectType type = m_label->parentAspect()->type(); 0421 if (type == AspectType::Worksheet) { 0422 auto* worksheet = static_cast<const Worksheet*>(m_label->parentAspect()); 0423 connect(worksheet->background(), &Background::firstColorChanged, this, &LabelWidget::updateBackground); 0424 } else if (type == AspectType::CartesianPlot) { 0425 auto* plotArea = static_cast<CartesianPlot*>(m_label->parentAspect())->plotArea(); 0426 connect(plotArea->background(), &Background::firstColorChanged, this, &LabelWidget::updateBackground); 0427 } else if (type == AspectType::CartesianPlotLegend) { 0428 auto* legend = static_cast<const CartesianPlotLegend*>(m_label->parentAspect()); 0429 connect(legend->background(), &Background::firstColorChanged, this, &LabelWidget::updateBackground); 0430 } else if (type == AspectType::Axis) { 0431 auto* plotArea = static_cast<CartesianPlot*>(m_label->parentAspect()->parentAspect())->plotArea(); 0432 connect(plotArea->background(), &Background::firstColorChanged, this, &LabelWidget::updateBackground); 0433 } 0434 } 0435 0436 /*! 0437 * enables/disables the "fixed label"-mode, used when displaying 0438 * the properties of axis' title label. 0439 * In this mode, in the "geometry"-part only the offset (offset to the axis) 0440 * and the rotation of the label are available. 0441 */ 0442 void LabelWidget::setFixedLabelMode(const bool b) { 0443 ui.lPositionX->setVisible(!b); 0444 ui.cbPositionX->setVisible(!b); 0445 ui.sbPositionX->setVisible(!b); 0446 ui.lPositionY->setVisible(!b); 0447 ui.cbPositionY->setVisible(!b); 0448 ui.sbPositionY->setVisible(!b); 0449 ui.lHorizontalAlignment->setVisible(!b); 0450 ui.cbHorizontalAlignment->setVisible(!b); 0451 ui.lVerticalAlignment->setVisible(!b); 0452 ui.cbVerticalAlignment->setVisible(!b); 0453 ui.lOffsetX->setVisible(b); 0454 ui.lOffsetY->setVisible(b); 0455 ui.sbOffsetX->setVisible(b); 0456 ui.sbOffsetY->setVisible(b); 0457 } 0458 0459 /*! 0460 * enables/disables all geometry relevant widgets. 0461 * Used when displaying legend's title label. 0462 */ 0463 void LabelWidget::setGeometryAvailable(const bool b) { 0464 ui.lGeometry->setVisible(b); 0465 ui.lPositionX->setVisible(b); 0466 ui.cbPositionX->setVisible(b); 0467 ui.sbPositionX->setVisible(b); 0468 ui.lPositionY->setVisible(b); 0469 ui.cbPositionY->setVisible(b); 0470 ui.sbPositionY->setVisible(b); 0471 ui.lHorizontalAlignment->setVisible(b); 0472 ui.cbHorizontalAlignment->setVisible(b); 0473 ui.lVerticalAlignment->setVisible(b); 0474 ui.cbVerticalAlignment->setVisible(b); 0475 ui.lOffsetX->setVisible(b); 0476 ui.lOffsetY->setVisible(b); 0477 ui.sbOffsetX->setVisible(b); 0478 ui.sbOffsetY->setVisible(b); 0479 ui.lRotation->setVisible(b); 0480 ui.sbRotation->setVisible(b); 0481 } 0482 0483 /*! 0484 * enables/disables all border relevant widgets. 0485 * Used when displaying legend's title label. 0486 */ 0487 void LabelWidget::setBorderAvailable(bool b) { 0488 ui.lBorder->setVisible(b); 0489 ui.lBorderShape->setVisible(b); 0490 ui.cbBorderShape->setVisible(b); 0491 ui.lBorderStyle->setVisible(b); 0492 ui.cbBorderStyle->setVisible(b); 0493 ui.lBorderColor->setVisible(b); 0494 ui.kcbBorderColor->setVisible(b); 0495 ui.lBorderWidth->setVisible(b); 0496 ui.sbBorderWidth->setVisible(b); 0497 ui.lBorderOpacity->setVisible(b); 0498 ui.sbBorderOpacity->setVisible(b); 0499 } 0500 0501 void LabelWidget::updateUnits() { 0502 const KConfigGroup group = Settings::group(QStringLiteral("Settings_General")); 0503 BaseDock::Units units = (BaseDock::Units)group.readEntry("Units", (int)BaseDock::Units::Metric); 0504 if (units == m_units) 0505 return; 0506 0507 m_units = units; 0508 CONDITIONAL_LOCK_RETURN; 0509 QString suffix; 0510 auto xPosition = ui.cbPositionX->currentIndex(); 0511 auto yPosition = ui.cbPositionY->currentIndex(); 0512 if (m_units == BaseDock::Units::Metric) { 0513 // convert from imperial to metric 0514 m_worksheetUnit = Worksheet::Unit::Centimeter; 0515 suffix = QLatin1String(" cm"); 0516 if (xPosition != static_cast<int>(WorksheetElement::HorizontalPosition::Relative)) 0517 ui.sbPositionX->setValue(ui.sbPositionX->value() * GSL_CONST_CGS_INCH); 0518 if (yPosition != static_cast<int>(WorksheetElement::VerticalPosition::Relative)) 0519 ui.sbPositionY->setValue(ui.sbPositionY->value() * GSL_CONST_CGS_INCH); 0520 } else { 0521 // convert from metric to imperial 0522 m_worksheetUnit = Worksheet::Unit::Inch; 0523 suffix = QLatin1String(" in"); 0524 if (xPosition != static_cast<int>(WorksheetElement::HorizontalPosition::Relative)) 0525 ui.sbPositionX->setValue(ui.sbPositionX->value() / GSL_CONST_CGS_INCH); 0526 if (yPosition != static_cast<int>(WorksheetElement::VerticalPosition::Relative)) 0527 ui.sbPositionY->setValue(ui.sbPositionY->value() / GSL_CONST_CGS_INCH); 0528 } 0529 0530 if (xPosition != static_cast<int>(WorksheetElement::HorizontalPosition::Relative)) 0531 ui.sbPositionX->setSuffix(suffix); 0532 if (yPosition != static_cast<int>(WorksheetElement::VerticalPosition::Relative)) 0533 ui.sbPositionY->setSuffix(suffix); 0534 } 0535 0536 void LabelWidget::updateLocale() { 0537 const auto numberLocale = QLocale(); 0538 ui.sbPositionX->setLocale(numberLocale); 0539 ui.sbPositionY->setLocale(numberLocale); 0540 ui.sbOffsetX->setLocale(numberLocale); 0541 ui.sbOffsetY->setLocale(numberLocale); 0542 ui.sbBorderWidth->setLocale(numberLocale); 0543 } 0544 0545 //********************************************************** 0546 //****** SLOTs for changes triggered in LabelWidget ******** 0547 //********************************************************** 0548 0549 // text formatting slots 0550 0551 void LabelWidget::textChanged() { 0552 // QDEBUG("############\n" << Q_FUNC_INFO << ", label text =" << m_label->text().text) 0553 CONDITIONAL_LOCK_RETURN; 0554 0555 const QString plainText = ui.teLabel->toPlainText(); 0556 QTextEdit te(ui.chbShowPlaceholderText->isChecked() ? m_label->text().textPlaceholder : m_label->text().text); 0557 bool plainTextChanged = plainText != te.toPlainText(); 0558 0559 auto mode = static_cast<TextLabel::Mode>(ui.cbMode->currentIndex()); 0560 switch (mode) { 0561 case TextLabel::Mode::LaTeX: 0562 case TextLabel::Mode::Markdown: { 0563 QString text = ui.teLabel->toPlainText(); 0564 TextLabel::TextWrapper wrapper; 0565 wrapper.mode = mode; 0566 0567 if (!ui.chbShowPlaceholderText->isChecked()) { 0568 if (plainTextChanged) { 0569 // set text only if the plain text change. otherwise the text is changed 0570 // already in the setter functions 0571 wrapper.text = text; 0572 for (auto* label : m_labelsList) { 0573 wrapper.textPlaceholder = label->text().textPlaceholder; 0574 wrapper.allowPlaceholder = label->text().allowPlaceholder; 0575 label->setText(wrapper); 0576 } 0577 } 0578 } else { 0579 // No need to compare if plainTextChanged 0580 // Change it always. 0581 wrapper.textPlaceholder = text; 0582 for (auto* label : m_labelsList) { 0583 wrapper.allowPlaceholder = label->text().allowPlaceholder; 0584 wrapper.text = label->text().text; 0585 label->setPlaceholderText(wrapper); 0586 } 0587 } 0588 break; 0589 } 0590 case TextLabel::Mode::Text: { 0591 // QDEBUG(Q_FUNC_INFO << ", color = " << m_label->fontColor()) 0592 // QDEBUG(Q_FUNC_INFO << ", background color = " << m_label->backgroundColor()) 0593 // QDEBUG(Q_FUNC_INFO << ", format color = " << ui.teLabel->currentCharFormat().foreground().color()) 0594 // QDEBUG(Q_FUNC_INFO << ", Plain TEXT = " << ui.teLabel->toPlainText() << '\n') 0595 // QDEBUG(Q_FUNC_INFO << ", OLD TEXT =" << m_label->text().text << '\n') 0596 // save an empty string instead of html with empty body if no text is in QTextEdit 0597 QString text; 0598 if (!ui.teLabel->toPlainText().isEmpty()) { 0599 // if the current or previous label text is empty, set the color first 0600 QTextEdit pte(m_label->text().text); // te with previous text 0601 if (m_label->text().text.isEmpty() || pte.toPlainText().isEmpty()) { 0602 // DEBUG("EMPTY TEXT") 0603 ui.teLabel->selectAll(); 0604 ui.teLabel->setTextColor(m_label->fontColor()); 0605 ui.teLabel->setTextBackgroundColor(m_label->backgroundColor()); 0606 // clear the selection after setting the color 0607 auto tc = ui.teLabel->textCursor(); 0608 tc.setPosition(tc.selectionEnd()); 0609 ui.teLabel->setTextCursor(tc); 0610 } 0611 0612 text = ui.teLabel->toHtml(); 0613 } 0614 0615 QDEBUG(Q_FUNC_INFO << ", NEW TEXT = " << text << '\n') 0616 TextLabel::TextWrapper wrapper(text, TextLabel::Mode::Text, true); 0617 // Don't set font color, because it is already in the html code 0618 // of the text. The font color is used to change the color for Latex text 0619 if (!ui.chbShowPlaceholderText->isChecked()) { 0620 if (plainTextChanged) { 0621 wrapper.text = text; 0622 for (auto* label : m_labelsList) { 0623 if (text.isEmpty()) { 0624 label->setFontColor(ui.kcbFontColor->color()); 0625 label->setBackgroundColor(ui.kcbBackgroundColor->color()); 0626 } 0627 wrapper.allowPlaceholder = label->text().allowPlaceholder; 0628 wrapper.textPlaceholder = label->text().textPlaceholder; 0629 label->setText(wrapper); 0630 } 0631 } 0632 } else { 0633 wrapper.textPlaceholder = text; 0634 for (auto* label : m_labelsList) { 0635 wrapper.allowPlaceholder = label->text().allowPlaceholder; 0636 wrapper.text = label->text().text; 0637 label->setPlaceholderText(wrapper); 0638 } 0639 } 0640 } 0641 } 0642 0643 // background color gets lost on every text change... 0644 updateBackground(); 0645 // DEBUG(Q_FUNC_INFO << " DONE\n#################################") 0646 } 0647 0648 /*! 0649 * \brief LabelWidget::charFormatChanged 0650 * \param format 0651 * Used to update the colors, font,... in the color font widgets to show the style of the selected text 0652 */ 0653 void LabelWidget::charFormatChanged(const QTextCharFormat& format) { 0654 auto mode = static_cast<TextLabel::Mode>(ui.cbMode->currentIndex()); 0655 if (mode != TextLabel::Mode::Text) 0656 return; 0657 0658 CONDITIONAL_LOCK_RETURN; 0659 0660 // update button state 0661 ui.tbFontBold->setChecked(ui.teLabel->fontWeight() == QFont::Bold); 0662 ui.tbFontItalic->setChecked(ui.teLabel->fontItalic()); 0663 ui.tbFontUnderline->setChecked(ui.teLabel->fontUnderline()); 0664 ui.tbFontStrikeOut->setChecked(format.fontStrikeOut()); 0665 ui.tbFontSuperScript->setChecked(format.verticalAlignment() == QTextCharFormat::AlignSuperScript); 0666 ui.tbFontSubScript->setChecked(format.verticalAlignment() == QTextCharFormat::AlignSubScript); 0667 0668 // font and colors 0669 QDEBUG(Q_FUNC_INFO << ", format color = " << format.foreground().color()) 0670 QDEBUG(Q_FUNC_INFO << ", label color = " << m_label->fontColor()) 0671 QDEBUG(Q_FUNC_INFO << ", text = " << ui.teLabel->toPlainText()) 0672 QDEBUG(Q_FUNC_INFO << ", label text = " << m_label->text().text) 0673 0674 // TEST 0675 if (ui.teLabel->toPlainText().isEmpty()) 0676 return; 0677 0678 // when text is empty the default color of format is black instead of the theme color! 0679 if (m_label->text().isHtml() && format.foreground().color().isValid() && !ui.teLabel->toPlainText().isEmpty()) 0680 ui.kcbFontColor->setColor(format.foreground().color()); 0681 else 0682 ui.kcbFontColor->setColor(m_label->fontColor()); 0683 0684 if (m_label->text().isHtml() && format.background().color().isValid() && !ui.teLabel->toPlainText().isEmpty()) 0685 ui.kcbBackgroundColor->setColor(format.background().color()); 0686 else 0687 ui.kcbBackgroundColor->setColor(m_label->backgroundColor()); 0688 0689 ui.kfontRequester->setFont(format.font()); 0690 } 0691 0692 // called when textlabel mode is changed 0693 void LabelWidget::labelModeChanged(TextLabel::Mode mode) { 0694 CONDITIONAL_LOCK_RETURN; 0695 0696 updateMode(mode); 0697 } 0698 0699 // Called when the combobox changes index 0700 void LabelWidget::modeChanged(int index) { 0701 auto mode = static_cast<TextLabel::Mode>(index); 0702 bool plain = (mode != TextLabel::Mode::Text); 0703 0704 labelModeChanged(mode); 0705 0706 CONDITIONAL_RETURN_NO_LOCK; // No lock, because multiple things are set by the feedback 0707 0708 QString text = plain ? ui.teLabel->toPlainText() : ui.teLabel->toHtml(); 0709 TextLabel::TextWrapper wrapper(text, mode, !plain); 0710 DEBUG(Q_FUNC_INFO << ", text = " << STDSTRING(wrapper.text)) 0711 for (auto* label : m_labelsList) 0712 label->setText(wrapper); 0713 } 0714 0715 void LabelWidget::fontColorChanged(const QColor& color) { 0716 CONDITIONAL_LOCK_RETURN; 0717 0718 auto mode = m_label->text().mode; 0719 if (mode == TextLabel::Mode::Text || (mode == TextLabel::Mode::LaTeX && !m_teXEnabled)) { 0720 SETLABELTEXTPROPERTY(setTextColor, color); 0721 if (!cursorHasSelection) { 0722 for (auto* label : m_labelsList) 0723 label->setFontColor(color); 0724 } 0725 } else { // LaTeX (enabled) or Markup mode 0726 for (auto* label : m_labelsList) 0727 label->setFontColor(color); 0728 } 0729 } 0730 0731 void LabelWidget::backgroundColorChanged(const QColor& color) { 0732 QDEBUG(Q_FUNC_INFO << ", color = " << color) 0733 CONDITIONAL_LOCK_RETURN; 0734 0735 auto mode = m_label->text().mode; 0736 DEBUG(Q_FUNC_INFO << ", tex enable = " << m_teXEnabled << ", mode = " << (int)mode) 0737 if (mode == TextLabel::Mode::Text || (mode == TextLabel::Mode::LaTeX && !m_teXEnabled)) { 0738 auto newColor(color); 0739 if (color.alpha() == 0) { // remove the transparency if it was set initially before. 0740 newColor.setAlpha(255); 0741 ui.kcbBackgroundColor->setColor(newColor); 0742 } 0743 SETLABELTEXTPROPERTY(setTextBackgroundColor, newColor) 0744 } else { // LaTeX (enabled) or Markup mode 0745 // Latex text does not support html code. For this the backgroundColor variable is used 0746 // Only single color background is supported 0747 for (auto* label : m_labelsList) 0748 label->setBackgroundColor(color); 0749 } 0750 } 0751 0752 void LabelWidget::fontSizeChanged(int value) { 0753 CONDITIONAL_LOCK_RETURN; 0754 0755 QFont font = m_label->teXFont(); 0756 font.setPointSize(value); 0757 for (auto* label : m_labelsList) 0758 label->setTeXFont(font); 0759 } 0760 0761 void LabelWidget::fontBoldChanged(bool checked) { 0762 CONDITIONAL_LOCK_RETURN; 0763 0764 QFont::Weight weight; 0765 if (checked) 0766 weight = QFont::Bold; 0767 else 0768 weight = QFont::Normal; 0769 SETLABELTEXTPROPERTY(setFontWeight, weight); 0770 } 0771 0772 void LabelWidget::fontItalicChanged(bool checked) { 0773 CONDITIONAL_LOCK_RETURN; 0774 0775 SETLABELTEXTPROPERTY(setFontItalic, checked); 0776 } 0777 0778 void LabelWidget::fontUnderlineChanged(bool checked) { 0779 CONDITIONAL_LOCK_RETURN; 0780 0781 SETLABELTEXTPROPERTY(setFontUnderline, checked); 0782 } 0783 0784 void LabelWidget::fontStrikeOutChanged(bool checked) { 0785 CONDITIONAL_LOCK_RETURN; 0786 0787 QTextCharFormat format = ui.teLabel->currentCharFormat(); 0788 format.setFontStrikeOut(checked); 0789 SETLABELTEXTPROPERTY(setCurrentCharFormat, format); 0790 } 0791 0792 void LabelWidget::fontSuperScriptChanged(bool checked) { 0793 CONDITIONAL_LOCK_RETURN; 0794 0795 QTextCharFormat format = ui.teLabel->currentCharFormat(); 0796 if (checked) 0797 format.setVerticalAlignment(QTextCharFormat::AlignSuperScript); 0798 else 0799 format.setVerticalAlignment(QTextCharFormat::AlignNormal); 0800 0801 SETLABELTEXTPROPERTY(setCurrentCharFormat, format); 0802 } 0803 0804 void LabelWidget::fontSubScriptChanged(bool checked) { 0805 CONDITIONAL_LOCK_RETURN; 0806 0807 QTextCharFormat format = ui.teLabel->currentCharFormat(); 0808 if (checked) 0809 format.setVerticalAlignment(QTextCharFormat::AlignSubScript); 0810 else 0811 format.setVerticalAlignment(QTextCharFormat::AlignNormal); 0812 0813 SETLABELTEXTPROPERTY(setCurrentCharFormat, format); 0814 } 0815 0816 void LabelWidget::fontChanged(const QFont& font) { 0817 CONDITIONAL_LOCK_RETURN; 0818 0819 // use mergeCurrentCharFormat(QTextCharFormat) instead of setFontFamily(font.family()), etc. 0820 // because this avoids textChanged() after every command 0821 QTextCharFormat format; 0822 format.setFontFamily(font.family()); 0823 #if (QT_VERSION >= QT_VERSION_CHECK(5, 13, 0)) 0824 format.setFontFamilies({font.family()}); // see QTBUG-80475 0825 #endif 0826 format.setFontPointSize(font.pointSize()); 0827 format.setFontItalic(font.italic()); 0828 format.setFontWeight(font.weight()); 0829 if (font.underline()) 0830 format.setUnderlineStyle(QTextCharFormat::UnderlineStyle::SingleUnderline); 0831 if (font.strikeOut()) 0832 format.setFontStrikeOut(font.strikeOut()); 0833 0834 // QDEBUG(Q_FUNC_INFO << ", BEFORE:" << ui.teLabel->toHtml()) 0835 SETLABELTEXTPROPERTY(mergeCurrentCharFormat, format); 0836 // QDEBUG(Q_FUNC_INFO << ", AFTER :" << ui.teLabel->toHtml()) 0837 } 0838 0839 void LabelWidget::teXFontChanged(const QFont& font) { 0840 CONDITIONAL_LOCK_RETURN; 0841 0842 for (auto* label : m_labelsList) 0843 label->setTeXFont(font); 0844 } 0845 0846 void LabelWidget::charMenu() { 0847 QMenu menu; 0848 KCharSelect selection(this, nullptr, KCharSelect::SearchLine | KCharSelect::CharacterTable | KCharSelect::BlockCombos | KCharSelect::HistoryButtons); 0849 QFont font = ui.teLabel->currentFont(); 0850 // use the system default size, otherwise the symbols might be hard to read 0851 // if the current label font size is too small 0852 font.setPointSize(QFont().pointSize()); 0853 selection.setCurrentFont(font); 0854 connect(&selection, &KCharSelect::charSelected, this, &LabelWidget::insertChar); 0855 connect(&selection, &KCharSelect::charSelected, &menu, &LabelWidget::close); 0856 0857 auto* widgetAction = new QWidgetAction(this); 0858 widgetAction->setDefaultWidget(&selection); 0859 menu.addAction(widgetAction); 0860 0861 QPoint pos(-menu.sizeHint().width() + ui.tbSymbols->width(), -menu.sizeHint().height()); 0862 menu.exec(ui.tbSymbols->mapToGlobal(pos)); 0863 } 0864 0865 void LabelWidget::insertChar(QChar c) { 0866 ui.teLabel->insertPlainText(QString(c)); 0867 } 0868 0869 void LabelWidget::dateTimeMenu() { 0870 m_dateTimeMenu->clear(); 0871 0872 const QString configPath = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation); 0873 const QString configFile = configPath + QLatin1String("/klanguageoverridesrc"); 0874 if (!QFile::exists(configFile)) { 0875 QDate date = QDate::currentDate(); 0876 m_dateTimeMenu->addSeparator()->setText(i18n("Date")); 0877 m_dateTimeMenu->addAction(date.toString(Qt::TextDate)); 0878 m_dateTimeMenu->addAction(date.toString(Qt::ISODate)); 0879 m_dateTimeMenu->addAction(QLocale::system().toString(date, QLocale::ShortFormat)); 0880 m_dateTimeMenu->addAction(QLocale::system().toString(date, QLocale::LongFormat)); 0881 m_dateTimeMenu->addAction(date.toString(Qt::RFC2822Date)); 0882 0883 QDateTime time = QDateTime::currentDateTime(); 0884 m_dateTimeMenu->addSeparator()->setText(i18n("Date and Time")); 0885 m_dateTimeMenu->addAction(time.toString(Qt::TextDate)); 0886 m_dateTimeMenu->addAction(time.toString(Qt::ISODate)); 0887 m_dateTimeMenu->addAction(QLocale::system().toString(time, QLocale::ShortFormat)); 0888 m_dateTimeMenu->addAction(QLocale::system().toString(time, QLocale::LongFormat)); 0889 m_dateTimeMenu->addAction(time.toString(Qt::RFC2822Date)); 0890 } else { 0891 // application language was changed: 0892 // determine the currently used language and use QLocale::toString() 0893 // to get the strings translated into the currently used language 0894 // TODO: why not use QLocale() ? 0895 QSettings settings(configFile, QSettings::IniFormat); 0896 settings.beginGroup(QLatin1String("Language")); 0897 QByteArray languageCode; 0898 languageCode = settings.value(qAppName(), languageCode).toByteArray(); 0899 QLocale locale(QString::fromLatin1(languageCode.data())); 0900 0901 QDate date = QDate::currentDate(); 0902 m_dateTimeMenu->addSeparator()->setText(i18n("Date")); 0903 m_dateTimeMenu->addAction(locale.toString(date, QLatin1String("ddd MMM d yyyy"))); // Qt::TextDate 0904 m_dateTimeMenu->addAction(locale.toString(date, QLatin1String("yyyy-MM-dd"))); // Qt::ISODate 0905 m_dateTimeMenu->addAction(locale.system().toString(date, QLocale::ShortFormat)); // Qt::SystemLocaleShortDate 0906 // no LongFormat here since it would contain strings in system's language which (potentially) is not the current application language 0907 m_dateTimeMenu->addAction(locale.toString(date, QLatin1String("dd MMM yyyy"))); // Qt::RFC2822Date 0908 0909 QDateTime time = QDateTime::currentDateTime(); 0910 m_dateTimeMenu->addSeparator()->setText(i18n("Date and Time")); 0911 m_dateTimeMenu->addAction(locale.toString(time, QLatin1String("ddd MMM d hh:mm:ss yyyy"))); // Qt::TextDate 0912 m_dateTimeMenu->addAction(locale.toString(time, QLatin1String("yyyy-MM-ddTHH:mm:ss"))); // Qt::ISODate 0913 m_dateTimeMenu->addAction(locale.system().toString(time, QLocale::ShortFormat)); // Qt::SystemLocaleShortDate 0914 // no LongFormat here since it would contain strings in system's language which (potentially) is not the current application language 0915 0916 // TODO: RFC2822 requires time zone but Qt QLocale::toString() seems to ignore TZD (time zone designator) completely, 0917 // which works correctly with QDateTime::toString() 0918 m_dateTimeMenu->addAction(locale.toString(time, QLatin1String("dd MMM yyyy hh:mm:ss"))); // Qt::RFC2822Date 0919 } 0920 0921 m_dateTimeMenu->exec(mapToGlobal(ui.tbDateTime->rect().bottomLeft())); 0922 } 0923 0924 void LabelWidget::insertDateTime(QAction* action) { 0925 ui.teLabel->insertPlainText(action->text().remove(QLatin1Char('&'))); 0926 } 0927 0928 // positioning using absolute coordinates 0929 /*! 0930 called when label's current horizontal position relative to its parent (left, center, right, relative) is changed. 0931 */ 0932 void LabelWidget::positionXChanged(int index) { 0933 CONDITIONAL_LOCK_RETURN; 0934 0935 auto position = m_label->position(); 0936 auto oldHorizontalPosition = position.horizontalPosition; 0937 position.horizontalPosition = TextLabel::HorizontalPosition(index); 0938 double x = 0.; 0939 if (position.horizontalPosition == WorksheetElement::HorizontalPosition::Relative) { 0940 switch (oldHorizontalPosition) { 0941 case WorksheetElement::HorizontalPosition::Left: 0942 case WorksheetElement::HorizontalPosition::Relative: 0943 break; 0944 case WorksheetElement::HorizontalPosition::Center: 0945 x = 0.5; 0946 break; 0947 case WorksheetElement::HorizontalPosition::Right: 0948 x = 1.0; 0949 } 0950 ui.sbPositionX->setSuffix(QStringLiteral(" %")); 0951 } else { 0952 if (m_units == Units::Metric) 0953 ui.sbPositionX->setSuffix(QStringLiteral(" cm")); 0954 else 0955 ui.sbPositionX->setSuffix(QStringLiteral(" in")); 0956 } 0957 0958 position.point.setX(x); 0959 ui.sbPositionX->setValue(100. * x); 0960 0961 for (auto* label : m_labelsList) 0962 label->setPosition(position); 0963 } 0964 0965 /*! 0966 called when label's current horizontal position relative to its parent (top, center, bottom, relative) is changed. 0967 */ 0968 void LabelWidget::positionYChanged(int index) { 0969 CONDITIONAL_LOCK_RETURN; 0970 0971 auto position = m_label->position(); 0972 auto oldVerticalPosition = position.verticalPosition; 0973 position.verticalPosition = TextLabel::VerticalPosition(index); 0974 double y = 0.; 0975 if (position.verticalPosition == WorksheetElement::VerticalPosition::Relative) { 0976 switch (oldVerticalPosition) { 0977 case WorksheetElement::VerticalPosition::Top: 0978 case WorksheetElement::VerticalPosition::Relative: 0979 break; 0980 case WorksheetElement::VerticalPosition::Center: 0981 y = 0.5; 0982 break; 0983 case WorksheetElement::VerticalPosition::Bottom: 0984 y = 1.0; 0985 } 0986 ui.sbPositionY->setSuffix(QStringLiteral(" %")); 0987 } else { 0988 if (m_units == Units::Metric) 0989 ui.sbPositionY->setSuffix(QStringLiteral(" cm")); 0990 else 0991 ui.sbPositionY->setSuffix(QStringLiteral(" in")); 0992 } 0993 0994 position.point.setY(y); 0995 ui.sbPositionY->setValue(100. * y); 0996 0997 for (auto* label : m_labelsList) 0998 label->setPosition(position); 0999 } 1000 1001 void LabelWidget::horizontalAlignmentChanged(int index) { 1002 CONDITIONAL_LOCK_RETURN; 1003 1004 for (auto* label : m_labelsList) 1005 label->setHorizontalAlignment(TextLabel::HorizontalAlignment(index)); 1006 } 1007 1008 void LabelWidget::verticalAlignmentChanged(int index) { 1009 CONDITIONAL_LOCK_RETURN; 1010 1011 for (auto* label : m_labelsList) 1012 label->setVerticalAlignment(TextLabel::VerticalAlignment(index)); 1013 } 1014 1015 void LabelWidget::customPositionXChanged(double value) { 1016 CONDITIONAL_RETURN_NO_LOCK; 1017 1018 for (auto* label : m_labelsList) { 1019 auto position = label->position(); 1020 if (position.horizontalPosition == WorksheetElement::HorizontalPosition::Relative) 1021 position.point.setX(value / 100.); 1022 else 1023 position.point.setX(Worksheet::convertToSceneUnits(value, m_worksheetUnit)); 1024 label->setPosition(position); 1025 } 1026 } 1027 1028 void LabelWidget::customPositionYChanged(double value) { 1029 CONDITIONAL_RETURN_NO_LOCK; 1030 1031 for (auto* label : m_labelsList) { 1032 auto position = label->position(); 1033 if (position.verticalPosition == WorksheetElement::VerticalPosition::Relative) 1034 position.point.setY(value / 100.); 1035 else 1036 position.point.setY(Worksheet::convertToSceneUnits(value, m_worksheetUnit)); 1037 label->setPosition(position); 1038 } 1039 } 1040 1041 // positioning using logical plot coordinates 1042 void LabelWidget::positionXLogicalChanged(double value) { 1043 CONDITIONAL_RETURN_NO_LOCK; 1044 1045 for (auto* label : m_labelsList) { 1046 auto pos = label->positionLogical(); 1047 pos.setX(value); 1048 label->setPositionLogical(pos); 1049 } 1050 } 1051 1052 void LabelWidget::positionXLogicalDateTimeChanged(qint64 value) { 1053 CONDITIONAL_LOCK_RETURN; 1054 1055 for (auto* label : m_labelsList) { 1056 auto pos = label->positionLogical(); 1057 pos.setX(value); 1058 label->setPositionLogical(pos); 1059 } 1060 } 1061 1062 void LabelWidget::positionYLogicalChanged(double value) { 1063 CONDITIONAL_RETURN_NO_LOCK; 1064 1065 for (auto* label : m_labelsList) { 1066 auto pos = label->positionLogical(); 1067 pos.setY(value); 1068 label->setPositionLogical(pos); 1069 } 1070 } 1071 1072 void LabelWidget::rotationChanged(int value) { 1073 CONDITIONAL_LOCK_RETURN; 1074 1075 for (auto* label : m_labelsList) 1076 label->setRotationAngle(value); 1077 } 1078 1079 void LabelWidget::offsetXChanged(double value) { 1080 CONDITIONAL_RETURN_NO_LOCK; 1081 1082 for (auto* axis : m_axesList) 1083 axis->setTitleOffsetX(Worksheet::convertToSceneUnits(value, Worksheet::Unit::Point)); 1084 } 1085 1086 void LabelWidget::offsetYChanged(double value) { 1087 CONDITIONAL_RETURN_NO_LOCK; 1088 1089 for (auto* axis : m_axesList) 1090 axis->setTitleOffsetY(Worksheet::convertToSceneUnits(value, Worksheet::Unit::Point)); 1091 } 1092 1093 void LabelWidget::lockChanged(bool locked) { 1094 CONDITIONAL_LOCK_RETURN; 1095 for (auto* label : m_labelsList) 1096 label->setLock(locked); 1097 } 1098 1099 // border 1100 void LabelWidget::borderShapeChanged(int index) { 1101 auto shape = (TextLabel::BorderShape)index; 1102 bool b = (shape != TextLabel::BorderShape::NoBorder); 1103 ui.lBorderStyle->setVisible(b); 1104 ui.cbBorderStyle->setVisible(b); 1105 ui.lBorderWidth->setVisible(b); 1106 ui.sbBorderWidth->setVisible(b); 1107 ui.lBorderColor->setVisible(b); 1108 ui.kcbBorderColor->setVisible(b); 1109 ui.lBorderOpacity->setVisible(b); 1110 ui.sbBorderOpacity->setVisible(b); 1111 1112 CONDITIONAL_LOCK_RETURN; 1113 1114 for (auto* label : m_labelsList) 1115 label->setBorderShape(shape); 1116 } 1117 1118 void LabelWidget::borderStyleChanged(int index) { 1119 CONDITIONAL_LOCK_RETURN; 1120 1121 auto penStyle = Qt::PenStyle(index); 1122 QPen pen; 1123 for (auto* label : m_labelsList) { 1124 pen = label->borderPen(); 1125 pen.setStyle(penStyle); 1126 label->setBorderPen(pen); 1127 } 1128 } 1129 1130 void LabelWidget::borderColorChanged(const QColor& color) { 1131 CONDITIONAL_LOCK_RETURN; 1132 1133 QPen pen; 1134 for (auto* label : m_labelsList) { 1135 pen = label->borderPen(); 1136 pen.setColor(color); 1137 label->setBorderPen(pen); 1138 } 1139 GuiTools::updatePenStyles(ui.cbBorderStyle, color); 1140 } 1141 1142 void LabelWidget::borderWidthChanged(double value) { 1143 CONDITIONAL_RETURN_NO_LOCK; 1144 1145 QPen pen; 1146 for (auto* label : m_labelsList) { 1147 pen = label->borderPen(); 1148 pen.setWidthF(Worksheet::convertToSceneUnits(value, Worksheet::Unit::Point)); 1149 label->setBorderPen(pen); 1150 } 1151 } 1152 1153 void LabelWidget::borderOpacityChanged(int value) { 1154 CONDITIONAL_LOCK_RETURN; 1155 1156 qreal opacity = (float)value / 100.; 1157 for (auto* label : m_labelsList) 1158 label->setBorderOpacity(opacity); 1159 } 1160 1161 /*! 1162 * \brief LabelWidget::bindingChanged 1163 * Bind TextLabel to the cartesian plot coords or not 1164 * \param checked 1165 */ 1166 void LabelWidget::bindingChanged(bool checked) { 1167 // widgets for positioning using absolute plot distances 1168 ui.lPositionX->setVisible(!checked); 1169 ui.cbPositionX->setVisible(!checked); 1170 ui.sbPositionX->setVisible(!checked); 1171 1172 ui.lPositionY->setVisible(!checked); 1173 ui.cbPositionY->setVisible(!checked); 1174 ui.sbPositionY->setVisible(!checked); 1175 1176 // widgets for positioning using logical plot coordinates 1177 const auto* plot = static_cast<const CartesianPlot*>(m_label->parent(AspectType::CartesianPlot)); 1178 if (plot && plot->xRangeFormatDefault() == RangeT::Format::DateTime) { 1179 ui.lPositionXLogicalDateTime->setVisible(checked); 1180 ui.dtePositionXLogical->setVisible(checked); 1181 1182 ui.lPositionXLogical->setVisible(false); 1183 ui.sbPositionXLogical->setVisible(false); 1184 } else { 1185 ui.lPositionXLogicalDateTime->setVisible(false); 1186 ui.dtePositionXLogical->setVisible(false); 1187 1188 ui.lPositionXLogical->setVisible(checked); 1189 ui.sbPositionXLogical->setVisible(checked); 1190 } 1191 1192 ui.lPositionYLogical->setVisible(checked); 1193 ui.sbPositionYLogical->setVisible(checked); 1194 1195 CONDITIONAL_LOCK_RETURN; 1196 1197 ui.chbBindLogicalPos->setChecked(checked); 1198 1199 for (auto* label : m_labelsList) 1200 label->setCoordinateBindingEnabled(checked); 1201 } 1202 1203 void LabelWidget::showPlaceholderTextChanged(bool checked) { 1204 CONDITIONAL_LOCK_RETURN; 1205 1206 if (!checked) { 1207 ui.teLabel->setEnabled(false); 1208 if (m_label->text().mode != TextLabel::Mode::Text) 1209 ui.teLabel->setText(m_label->text().text); 1210 else 1211 ui.teLabel->setHtml(m_label->text().text); 1212 } else { 1213 ui.teLabel->setEnabled(true); 1214 if (m_label->text().mode != TextLabel::Mode::Text) 1215 ui.teLabel->setText(m_label->text().textPlaceholder); 1216 else 1217 ui.teLabel->setHtml(m_label->text().textPlaceholder); 1218 } 1219 } 1220 1221 //********************************************************* 1222 //****** SLOTs for changes triggered in TextLabel ********* 1223 //********************************************************* 1224 void LabelWidget::labelTextWrapperChanged(const TextLabel::TextWrapper& text) { 1225 CONDITIONAL_LOCK_RETURN; 1226 1227 // save and restore the current cursor position after changing the text 1228 auto cursor = ui.teLabel->textCursor(); 1229 int position = cursor.position(); 1230 if (!ui.chbShowPlaceholderText->isChecked()) { 1231 if (text.mode != TextLabel::Mode::Text) 1232 ui.teLabel->setText(text.text); 1233 else 1234 ui.teLabel->setHtml(text.text); 1235 } else { 1236 if (text.mode != TextLabel::Mode::Text) 1237 ui.teLabel->setText(text.textPlaceholder); 1238 else 1239 ui.teLabel->setHtml(text.textPlaceholder); 1240 } 1241 cursor.movePosition(QTextCursor::Start); 1242 cursor.movePosition(QTextCursor::Right, QTextCursor::MoveAnchor, position); 1243 ui.teLabel->setTextCursor(cursor); 1244 1245 const int index = static_cast<int>(text.mode); 1246 ui.cbMode->setCurrentIndex(index); 1247 this->labelModeChanged(text.mode); 1248 } 1249 1250 /*! 1251 * \brief Highlights the text field if wrong latex syntax was used (null image was produced) 1252 * or something else went wrong during rendering (\sa ExpressionTextEdit::validateExpression()) 1253 */ 1254 void LabelWidget::labelTeXImageUpdated(const TeXRenderer::Result& result) { 1255 if (!result.successful) { 1256 if (ui.teLabel->styleSheet().isEmpty()) 1257 SET_WARNING_STYLE(ui.teLabel) 1258 m_messageWidget->setText(result.errorMessage); 1259 m_messageWidget->setMaximumWidth(ui.teLabel->width()); 1260 } else 1261 ui.teLabel->setStyleSheet(QString()); 1262 1263 m_messageWidget->setVisible(!result.successful); 1264 } 1265 1266 void LabelWidget::labelTeXFontChanged(const QFont& font) { 1267 CONDITIONAL_LOCK_RETURN; 1268 ui.kfontRequesterTeX->setFont(font); 1269 ui.sbFontSize->setValue(font.pointSize()); 1270 } 1271 1272 // this function is only called when the theme is changed. Otherwise the color is coded in the html text. 1273 // when the theme changes, the whole text should change color regardless of the color it has 1274 void LabelWidget::labelFontColorChanged(const QColor& color) { 1275 Q_EMIT labelFontColorChangedSignal(color); 1276 1277 CONDITIONAL_LOCK_RETURN; 1278 ui.kcbFontColor->setColor(color); 1279 ui.teLabel->selectAll(); 1280 ui.teLabel->setTextColor(color); 1281 } 1282 1283 void LabelWidget::labelPositionChanged(const TextLabel::PositionWrapper& position) { 1284 CONDITIONAL_LOCK_RETURN; 1285 1286 ui.cbPositionX->setCurrentIndex(static_cast<int>(position.horizontalPosition)); 1287 ui.cbPositionY->setCurrentIndex(static_cast<int>(position.verticalPosition)); 1288 if (position.horizontalPosition == WorksheetElement::HorizontalPosition::Relative) { 1289 ui.sbPositionX->setValue(position.point.x() * 100.); 1290 ui.sbPositionX->setSuffix(QStringLiteral(" %")); 1291 } else 1292 ui.sbPositionX->setValue(Worksheet::convertFromSceneUnits(position.point.x(), m_worksheetUnit)); 1293 1294 if (position.verticalPosition == WorksheetElement::VerticalPosition::Relative) { 1295 ui.sbPositionY->setValue(position.point.y() * 100.); 1296 ui.sbPositionY->setSuffix(QStringLiteral(" %")); 1297 } else 1298 ui.sbPositionY->setValue(Worksheet::convertFromSceneUnits(position.point.y(), m_worksheetUnit)); 1299 } 1300 1301 void LabelWidget::labelHorizontalAlignmentChanged(TextLabel::HorizontalAlignment index) { 1302 CONDITIONAL_LOCK_RETURN; 1303 ui.cbHorizontalAlignment->setCurrentIndex(static_cast<int>(index)); 1304 } 1305 1306 void LabelWidget::labelVerticalAlignmentChanged(TextLabel::VerticalAlignment index) { 1307 CONDITIONAL_LOCK_RETURN; 1308 ui.cbVerticalAlignment->setCurrentIndex(static_cast<int>(index)); 1309 } 1310 1311 void LabelWidget::labelCoordinateBindingEnabledChanged(bool enabled) { 1312 CONDITIONAL_LOCK_RETURN; 1313 bindingChanged(enabled); 1314 } 1315 1316 void LabelWidget::labelPositionLogicalChanged(QPointF pos) { 1317 CONDITIONAL_LOCK_RETURN; 1318 ui.sbPositionXLogical->setValue(pos.x()); 1319 ui.dtePositionXLogical->setMSecsSinceEpochUTC(pos.x()); 1320 ui.sbPositionYLogical->setValue(pos.y()); 1321 // TODO: why not ui.dtePositionYLogical->setMSecsSinceEpochUTC(pos.y()); 1322 } 1323 1324 // this function is only called when the theme is changed. Otherwise the color is coded in the html text. 1325 // when the theme changes, the whole text should change color regardless of the color it has 1326 void LabelWidget::labelBackgroundColorChanged(const QColor& color) { 1327 QDEBUG(Q_FUNC_INFO << ", color =" << color) 1328 CONDITIONAL_LOCK_RETURN; 1329 ui.kcbBackgroundColor->setColor(color); 1330 1331 auto mode = static_cast<TextLabel::Mode>(ui.cbMode->currentIndex()); 1332 if (mode != TextLabel::Mode::Text) 1333 return; 1334 1335 ui.teLabel->selectAll(); 1336 ui.teLabel->setTextBackgroundColor(color); 1337 } 1338 1339 void LabelWidget::labelOffsetXChanged(qreal offset) { 1340 CONDITIONAL_LOCK_RETURN; 1341 ui.sbOffsetX->setValue(Worksheet::convertFromSceneUnits(offset, Worksheet::Unit::Point)); 1342 } 1343 1344 void LabelWidget::labelOffsetYChanged(qreal offset) { 1345 CONDITIONAL_LOCK_RETURN; 1346 ui.sbOffsetY->setValue(Worksheet::convertFromSceneUnits(offset, Worksheet::Unit::Point)); 1347 } 1348 1349 void LabelWidget::labelRotationAngleChanged(qreal angle) { 1350 CONDITIONAL_LOCK_RETURN; 1351 ui.sbRotation->setValue(angle); 1352 } 1353 1354 void LabelWidget::labelLockChanged(bool on) { 1355 CONDITIONAL_LOCK_RETURN; 1356 ui.chbLock->setChecked(on); 1357 } 1358 1359 // border 1360 void LabelWidget::labelBorderShapeChanged(TextLabel::BorderShape shape) { 1361 CONDITIONAL_LOCK_RETURN; 1362 ui.cbBorderShape->setCurrentIndex(static_cast<int>(shape)); 1363 } 1364 1365 void LabelWidget::labelBorderPenChanged(const QPen& pen) { 1366 CONDITIONAL_LOCK_RETURN; 1367 if (ui.cbBorderStyle->currentIndex() != pen.style()) 1368 ui.cbBorderStyle->setCurrentIndex(pen.style()); 1369 if (ui.kcbBorderColor->color() != pen.color()) 1370 ui.kcbBorderColor->setColor(pen.color()); 1371 // Feedback needed therefore no condition 1372 ui.sbBorderWidth->setValue(Worksheet::convertFromSceneUnits(pen.widthF(), Worksheet::Unit::Point)); 1373 } 1374 1375 void LabelWidget::labelBorderOpacityChanged(float value) { 1376 CONDITIONAL_LOCK_RETURN; 1377 float v = (float)value * 100.; 1378 ui.sbBorderOpacity->setValue(v); 1379 } 1380 1381 void LabelWidget::labelCartesianPlotParent(bool on) { 1382 CONDITIONAL_LOCK_RETURN; 1383 ui.chbBindLogicalPos->setVisible(on); 1384 if (!on) 1385 ui.chbBindLogicalPos->setChecked(false); 1386 } 1387 1388 //********************************************************** 1389 //******************** SETTINGS **************************** 1390 //********************************************************** 1391 void LabelWidget::load() { 1392 if (!m_label) 1393 return; 1394 1395 CONDITIONAL_LOCK_RETURN; 1396 1397 ui.chbVisible->setChecked(m_label->isVisible()); 1398 ui.chbLock->setChecked(m_label->isLocked()); 1399 1400 // don't show checkbox if Placeholder feature not used 1401 bool allowPlaceholder = m_label->text().allowPlaceholder; 1402 ui.chbShowPlaceholderText->setVisible(allowPlaceholder); 1403 ui.chbShowPlaceholderText->setEnabled(allowPlaceholder); 1404 ui.chbShowPlaceholderText->setChecked(allowPlaceholder); 1405 1406 // Text 1407 const auto mode = m_label->text().mode; 1408 ui.cbMode->setCurrentIndex(static_cast<int>(mode)); 1409 this->updateMode(mode); 1410 1411 if (!allowPlaceholder) { 1412 if (mode == TextLabel::Mode::Text) { 1413 ui.teLabel->setHtml(m_label->text().text); 1414 ui.teLabel->selectAll(); // must be done to retrieve font 1415 ui.kfontRequester->setFont(ui.teLabel->currentFont()); 1416 } else 1417 ui.teLabel->setText(m_label->text().text); 1418 1419 } else { 1420 if (mode == TextLabel::Mode::Text) { 1421 ui.teLabel->setHtml(m_label->text().textPlaceholder); 1422 ui.teLabel->selectAll(); // must be done to retrieve font 1423 ui.kfontRequester->setFont(ui.teLabel->currentFont()); 1424 } else 1425 ui.teLabel->setText(m_label->text().textPlaceholder); 1426 } 1427 1428 auto format = ui.teLabel->currentCharFormat(); 1429 1430 // when text is empty the default color of format is black instead of the theme color! 1431 if (m_label->text().isHtml() && format.foreground().color().isValid() && !ui.teLabel->toPlainText().isEmpty()) 1432 ui.kcbFontColor->setColor(format.foreground().color()); 1433 else 1434 ui.kcbFontColor->setColor(m_label->fontColor()); 1435 1436 if (m_label->text().isHtml() && format.background().color().isValid() && !ui.teLabel->toPlainText().isEmpty()) { 1437 // The html below does not contain any information about the background color. So qt uses black which is not correct 1438 // "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" \"http://www.w3.org/TR/REC-html40/strict.dtd\">\n<html><head><meta name=\"qrichtext\" 1439 // content=\"1\" /><style type=\"text/css\">\np, li { white-space: pre-wrap; }\n</style></head><body style=\" font-family:'Noto Sans'; font-size:10pt; 1440 // font-weight:400; font-style:normal;\">\n<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; 1441 // text-indent:0px;\"><span style=\" color:#000000;\">1</span></p></body></html>" 1442 if (m_label->text().text.contains(QStringLiteral("background-color"))) 1443 ui.kcbBackgroundColor->setColor(format.background().color()); 1444 else 1445 ui.kcbBackgroundColor->setColor(QColor(Qt::GlobalColor::transparent)); 1446 } else 1447 ui.kcbBackgroundColor->setColor(m_label->backgroundColor()); 1448 1449 ui.kfontRequesterTeX->setFont(m_label->teXFont()); 1450 ui.sbFontSize->setValue(m_label->teXFont().pointSize()); 1451 1452 ui.tbFontBold->setChecked(ui.teLabel->fontWeight() == QFont::Bold); 1453 ui.tbFontItalic->setChecked(ui.teLabel->fontItalic()); 1454 ui.tbFontUnderline->setChecked(ui.teLabel->fontUnderline()); 1455 ui.tbFontStrikeOut->setChecked(format.fontStrikeOut()); 1456 ui.tbFontSuperScript->setChecked(format.verticalAlignment() == QTextCharFormat::AlignSuperScript); 1457 ui.tbFontSubScript->setChecked(format.verticalAlignment() == QTextCharFormat::AlignSubScript); 1458 1459 // move the cursor to the end 1460 QTextCursor cursor = ui.teLabel->textCursor(); 1461 cursor.movePosition(QTextCursor::End); 1462 ui.teLabel->setTextCursor(cursor); 1463 // ui.teLabel->setFocus(); // Do not set focus, otherwise the WorksheetView is not able to catch key input events! 1464 1465 // Geometry 1466 // widgets for positioning using absolute plot distances 1467 ui.cbPositionX->setCurrentIndex((int)m_label->position().horizontalPosition); 1468 // positionXChanged(ui.cbPositionX->currentIndex()); 1469 if (m_label->position().horizontalPosition == WorksheetElement::HorizontalPosition::Relative) { 1470 ui.sbPositionX->setValue(m_label->position().point.x() * 100); 1471 ui.sbPositionX->setSuffix(QStringLiteral(" %")); 1472 } else 1473 ui.sbPositionX->setValue(Worksheet::convertFromSceneUnits(m_label->position().point.x(), m_worksheetUnit)); 1474 ui.cbPositionY->setCurrentIndex((int)m_label->position().verticalPosition); 1475 // positionYChanged(ui.cbPositionY->currentIndex()); 1476 if (m_label->position().verticalPosition == WorksheetElement::VerticalPosition::Relative) { 1477 ui.sbPositionY->setValue(m_label->position().point.y() * 100); 1478 ui.sbPositionY->setSuffix(QStringLiteral(" %")); 1479 } else 1480 ui.sbPositionY->setValue(Worksheet::convertFromSceneUnits(m_label->position().point.y(), m_worksheetUnit)); 1481 1482 ui.cbHorizontalAlignment->setCurrentIndex((int)m_label->horizontalAlignment()); 1483 ui.cbVerticalAlignment->setCurrentIndex((int)m_label->verticalAlignment()); 1484 1485 // widgets for positioning using logical plot coordinates 1486 bool allowLogicalCoordinates = (m_label->plot() != nullptr); 1487 ui.chbBindLogicalPos->setVisible(allowLogicalCoordinates); 1488 1489 if (allowLogicalCoordinates) { 1490 const auto* plot = static_cast<const CartesianPlot*>(m_label->plot()); 1491 if (plot->xRangeFormatDefault() == RangeT::Format::Numeric) { 1492 ui.lPositionXLogical->show(); 1493 ui.sbPositionXLogical->show(); 1494 ui.lPositionXLogicalDateTime->hide(); 1495 ui.dtePositionXLogical->hide(); 1496 1497 ui.sbPositionXLogical->setValue(m_label->positionLogical().x()); 1498 ui.sbPositionYLogical->setValue(m_label->positionLogical().y()); 1499 } else { // DateTime 1500 ui.lPositionXLogical->hide(); 1501 ui.sbPositionXLogical->hide(); 1502 ui.lPositionXLogicalDateTime->show(); 1503 ui.dtePositionXLogical->show(); 1504 1505 ui.dtePositionXLogical->setDisplayFormat(plot->rangeDateTimeFormat(Dimension::X)); 1506 ui.dtePositionXLogical->setMSecsSinceEpochUTC(m_label->positionLogical().x()); 1507 } 1508 1509 ui.chbBindLogicalPos->setChecked(m_label->coordinateBindingEnabled()); 1510 bindingChanged(m_label->coordinateBindingEnabled()); 1511 } else { 1512 ui.lPositionXLogical->hide(); 1513 ui.sbPositionXLogical->hide(); 1514 ui.lPositionYLogical->hide(); 1515 ui.sbPositionYLogical->hide(); 1516 ui.lPositionXLogicalDateTime->hide(); 1517 ui.dtePositionXLogical->hide(); 1518 } 1519 1520 // offsets, available for axis label only 1521 if (!m_axesList.isEmpty()) { 1522 ui.sbOffsetX->setValue(Worksheet::convertFromSceneUnits(m_axesList.first()->titleOffsetX(), Worksheet::Unit::Point)); 1523 ui.sbOffsetY->setValue(Worksheet::convertFromSceneUnits(m_axesList.first()->titleOffsetY(), Worksheet::Unit::Point)); 1524 } 1525 ui.sbRotation->setValue(m_label->rotationAngle()); 1526 1527 // don't show if binding not enabled. example: axis titles 1528 // Border 1529 ui.cbBorderShape->setCurrentIndex(static_cast<int>(m_label->borderShape())); 1530 borderShapeChanged(ui.cbBorderShape->currentIndex()); 1531 ui.kcbBorderColor->setColor(m_label->borderPen().color()); 1532 ui.cbBorderStyle->setCurrentIndex((int)m_label->borderPen().style()); 1533 ui.sbBorderWidth->setValue(Worksheet::convertFromSceneUnits(m_label->borderPen().widthF(), Worksheet::Unit::Point)); 1534 ui.sbBorderOpacity->setValue(round(m_label->borderOpacity() * 100)); 1535 GuiTools::updatePenStyles(ui.cbBorderStyle, ui.kcbBorderColor->color()); 1536 } 1537 1538 // General updater function to update the dock (used also in the load method) 1539 void LabelWidget::updateMode(TextLabel::Mode mode) { 1540 bool plain = (mode != TextLabel::Mode::Text); 1541 1542 // hide text editing elements if TeX-option is used 1543 ui.tbFontBold->setVisible(!plain); 1544 ui.tbFontItalic->setVisible(!plain); 1545 1546 // TODO: https://bugreports.qt.io/browse/QTBUG-25420 1547 // ui.tbFontUnderline->setVisible(!plain); 1548 // ui.tbFontStrikeOut->setVisible(!plain); 1549 1550 ui.tbFontSubScript->setVisible(!plain); 1551 ui.tbFontSuperScript->setVisible(!plain); 1552 1553 ui.lFont->setVisible(!plain); 1554 ui.kfontRequester->setVisible(!plain); 1555 1556 if (plain) { 1557 // reset all applied formattings when switching from html to tex mode 1558 QTextCursor cursor = ui.teLabel->textCursor(); 1559 int position = cursor.position(); 1560 ui.teLabel->selectAll(); 1561 QTextCharFormat format; 1562 ui.teLabel->setCurrentCharFormat(format); 1563 cursor.movePosition(QTextCursor::Right, QTextCursor::MoveAnchor, position); 1564 ui.teLabel->setTextCursor(cursor); 1565 1566 #ifdef HAVE_KF5_SYNTAX_HIGHLIGHTING 1567 m_highlighter->setDocument(ui.teLabel->document()); 1568 if (mode == TextLabel::Mode::LaTeX) 1569 m_highlighter->setDefinition(m_repository.definitionForName(QLatin1String("LaTeX"))); 1570 else 1571 m_highlighter->setDefinition(m_repository.definitionForName(QLatin1String("Markdown"))); 1572 #endif 1573 KConfigGroup conf = Settings::group(QLatin1String("Settings_Worksheet")); 1574 QString engine = conf.readEntry(QLatin1String("LaTeXEngine"), ""); 1575 if (engine == QLatin1String("xelatex") || engine == QLatin1String("lualatex")) { 1576 ui.lFontTeX->setVisible(true); 1577 ui.kfontRequesterTeX->setVisible(true); 1578 ui.lFontSize->setVisible(false); 1579 ui.sbFontSize->setVisible(false); 1580 } else { 1581 ui.lFontTeX->setVisible(false); 1582 ui.kfontRequesterTeX->setVisible(false); 1583 ui.lFontSize->setVisible(true); 1584 ui.sbFontSize->setVisible(true); 1585 } 1586 1587 // update colors 1588 ui.kcbFontColor->setColor(m_label->fontColor()); 1589 ui.kcbBackgroundColor->setColor(m_label->backgroundColor()); 1590 } else { 1591 #ifdef HAVE_KF5_SYNTAX_HIGHLIGHTING 1592 m_highlighter->setDocument(nullptr); 1593 #endif 1594 ui.lFontTeX->setVisible(false); 1595 ui.kfontRequesterTeX->setVisible(false); 1596 ui.lFontSize->setVisible(false); 1597 ui.sbFontSize->setVisible(false); 1598 } 1599 1600 updateBackground(); 1601 1602 // when switching to non-LaTeX mode, set the background color to white just for the case the latex code provided by the user 1603 // in the TeX-mode is not valid and the background was set to red (s.a. LabelWidget::labelTeXImageUpdated()) 1604 if (mode != TextLabel::Mode::LaTeX) { 1605 ui.teLabel->setStyleSheet(QString()); 1606 m_messageWidget->setVisible(false); 1607 } 1608 } 1609 1610 void LabelWidget::loadConfig(KConfigGroup& group) { 1611 if (!m_label) 1612 return; 1613 1614 // Text 1615 ui.cbMode->setCurrentIndex(group.readEntry("Mode", static_cast<int>(m_label->text().mode))); 1616 this->modeChanged(ui.cbMode->currentIndex()); 1617 ui.sbFontSize->setValue(group.readEntry("TeXFontSize", m_label->teXFont().pointSize())); 1618 ui.kcbFontColor->setColor(group.readEntry("FontColor", m_label->fontColor())); 1619 ui.kcbBackgroundColor->setColor(group.readEntry("BackgroundColor", m_label->backgroundColor())); 1620 ui.kfontRequesterTeX->setFont(group.readEntry("TeXFont", m_label->teXFont())); 1621 1622 // Geometry 1623 ui.cbPositionX->setCurrentIndex(group.readEntry("PositionX", (int)m_label->position().horizontalPosition)); 1624 ui.sbPositionX->setValue(Worksheet::convertFromSceneUnits(group.readEntry("PositionXValue", m_label->position().point.x()), m_worksheetUnit)); 1625 ui.cbPositionY->setCurrentIndex(group.readEntry("PositionY", (int)m_label->position().verticalPosition)); 1626 ui.sbPositionY->setValue(Worksheet::convertFromSceneUnits(group.readEntry("PositionYValue", m_label->position().point.y()), m_worksheetUnit)); 1627 1628 if (!m_axesList.isEmpty()) { 1629 ui.sbOffsetX->setValue(Worksheet::convertFromSceneUnits(group.readEntry("OffsetX", m_axesList.first()->titleOffsetX()), Worksheet::Unit::Point)); 1630 ui.sbOffsetY->setValue(Worksheet::convertFromSceneUnits(group.readEntry("OffsetY", m_axesList.first()->titleOffsetY()), Worksheet::Unit::Point)); 1631 } 1632 ui.cbHorizontalAlignment->setCurrentIndex(group.readEntry("HorizontalAlignment", (int)m_label->horizontalAlignment())); 1633 ui.cbVerticalAlignment->setCurrentIndex(group.readEntry("VerticalAlignment", (int)m_label->verticalAlignment())); 1634 ui.sbRotation->setValue(group.readEntry("Rotation", m_label->rotationAngle())); 1635 1636 // Border 1637 ui.cbBorderShape->setCurrentIndex(group.readEntry("BorderShape").toInt()); 1638 ui.kcbBorderColor->setColor(group.readEntry("BorderColor", m_label->borderPen().color())); 1639 ui.cbBorderStyle->setCurrentIndex(group.readEntry("BorderStyle", (int)m_label->borderPen().style())); 1640 ui.sbBorderWidth->setValue(Worksheet::convertFromSceneUnits(group.readEntry("BorderWidth", m_label->borderPen().widthF()), Worksheet::Unit::Point)); 1641 ui.sbBorderOpacity->setValue(group.readEntry("BorderOpacity", m_label->borderOpacity()) * 100); 1642 } 1643 1644 void LabelWidget::saveConfig(KConfigGroup& group) { 1645 // Text 1646 group.writeEntry("Mode", ui.cbMode->currentIndex()); 1647 group.writeEntry("FontColor", ui.kcbFontColor->color()); 1648 group.writeEntry("BackgroundColor", ui.kcbBackgroundColor->color()); 1649 group.writeEntry("TeXFont", ui.kfontRequesterTeX->font()); 1650 1651 // Geometry 1652 group.writeEntry("PositionX", ui.cbPositionX->currentIndex()); 1653 group.writeEntry("PositionXValue", Worksheet::convertToSceneUnits(ui.sbPositionX->value(), m_worksheetUnit)); 1654 group.writeEntry("PositionY", ui.cbPositionY->currentIndex()); 1655 group.writeEntry("PositionYValue", Worksheet::convertToSceneUnits(ui.sbPositionY->value(), m_worksheetUnit)); 1656 1657 if (!m_axesList.isEmpty()) { 1658 group.writeEntry("OffsetX", Worksheet::convertToSceneUnits(ui.sbOffsetX->value(), Worksheet::Unit::Point)); 1659 group.writeEntry("OffsetY", Worksheet::convertToSceneUnits(ui.sbOffsetY->value(), Worksheet::Unit::Point)); 1660 } 1661 group.writeEntry("HorizontalAlignment", ui.cbHorizontalAlignment->currentIndex()); 1662 group.writeEntry("VerticalAlignment", ui.cbVerticalAlignment->currentIndex()); 1663 group.writeEntry("Rotation", ui.sbRotation->value()); 1664 1665 // Border 1666 group.writeEntry("BorderShape", ui.cbBorderShape->currentIndex()); 1667 group.writeEntry("BorderStyle", ui.cbBorderStyle->currentIndex()); 1668 group.writeEntry("BorderColor", ui.kcbBorderColor->color()); 1669 group.writeEntry("BorderWidth", Worksheet::convertToSceneUnits(ui.sbBorderWidth->value(), Worksheet::Unit::Point)); 1670 group.writeEntry("BorderOpacity", ui.sbBorderOpacity->value() / 100.0); 1671 }