File indexing completed on 2024-04-28 15:51:40
0001 /* 0002 SPDX-FileCopyrightText: 2006 Pino Toscano <pino@kde.org> 0003 0004 SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include "annotationwidgets.h" 0008 0009 // qt/kde includes 0010 #include <KColorButton> 0011 #include <KComboBox> 0012 #include <KFontRequester> 0013 #include <KFormat> 0014 #include <KLocalizedString> 0015 #include <KMessageBox> 0016 #include <KMessageWidget> 0017 #include <QCheckBox> 0018 #include <QDebug> 0019 #include <QFileDialog> 0020 #include <QFormLayout> 0021 #include <QGroupBox> 0022 #include <QGuiApplication> 0023 #include <QIcon> 0024 #include <QLabel> 0025 #include <QLayout> 0026 #include <QList> 0027 #include <QMimeDatabase> 0028 #include <QPair> 0029 #include <QSize> 0030 #include <QSpinBox> 0031 #include <QVariant> 0032 0033 #include "core/annotations.h" 0034 #include "core/annotations_p.h" 0035 #include "core/document.h" 0036 #include "core/document_p.h" 0037 #include "core/page_p.h" 0038 #include "gui/guiutils.h" 0039 #include "gui/pagepainter.h" 0040 0041 #define FILEATTACH_ICONSIZE 48 0042 0043 PixmapPreviewSelector::PixmapPreviewSelector(QWidget *parent, PreviewPosition position) 0044 : QWidget(parent) 0045 , m_previewPosition(position) 0046 { 0047 QVBoxLayout *mainlay = new QVBoxLayout(this); 0048 mainlay->setContentsMargins(0, 0, 0, 0); 0049 QHBoxLayout *toplay = new QHBoxLayout; 0050 toplay->setContentsMargins(0, 0, 0, 0); 0051 mainlay->addLayout(toplay); 0052 m_comboItems = new KComboBox(this); 0053 toplay->addWidget(m_comboItems); 0054 m_stampPushButton = new QPushButton(QIcon::fromTheme(QStringLiteral("document-open")), QString(), this); 0055 m_stampPushButton->setVisible(false); 0056 m_stampPushButton->setToolTip(i18nc("@info:tooltip", "Select a custom stamp symbol from file")); 0057 toplay->addWidget(m_stampPushButton); 0058 m_iconLabel = new QLabel(this); 0059 switch (m_previewPosition) { 0060 case Side: 0061 toplay->addWidget(m_iconLabel); 0062 break; 0063 case Below: 0064 mainlay->addWidget(m_iconLabel); 0065 mainlay->setAlignment(m_iconLabel, Qt::AlignHCenter); 0066 break; 0067 } 0068 m_iconLabel->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); 0069 m_iconLabel->setAlignment(Qt::AlignCenter); 0070 m_iconLabel->setFrameStyle(QFrame::StyledPanel); 0071 setPreviewSize(32); 0072 0073 setFocusPolicy(Qt::TabFocus); 0074 setFocusProxy(m_comboItems); 0075 0076 connect(m_comboItems, &QComboBox::currentIndexChanged, this, [this](int index) { iconComboChanged(m_comboItems->itemText(index)); }); 0077 connect(m_comboItems, &QComboBox::editTextChanged, this, &PixmapPreviewSelector::iconComboChanged); 0078 connect(m_stampPushButton, &QPushButton::clicked, this, &PixmapPreviewSelector::selectCustomStamp); 0079 } 0080 0081 PixmapPreviewSelector::~PixmapPreviewSelector() 0082 { 0083 } 0084 0085 void PixmapPreviewSelector::setIcon(const QString &icon) 0086 { 0087 int id = m_comboItems->findData(QVariant(icon), Qt::UserRole, Qt::MatchFixedString); 0088 if (id == -1) { 0089 id = m_comboItems->findText(icon, Qt::MatchFixedString); 0090 } 0091 if (id > -1) { 0092 m_comboItems->setCurrentIndex(id); 0093 } else if (m_comboItems->isEditable()) { 0094 m_comboItems->addItem(icon, QVariant(icon)); 0095 m_comboItems->setCurrentIndex(m_comboItems->findText(icon, Qt::MatchFixedString)); 0096 } 0097 } 0098 0099 QString PixmapPreviewSelector::icon() const 0100 { 0101 return m_icon; 0102 } 0103 0104 void PixmapPreviewSelector::addItem(const QString &item, const QString &id) 0105 { 0106 m_comboItems->addItem(item, QVariant(id)); 0107 setIcon(m_icon); 0108 } 0109 0110 void PixmapPreviewSelector::setPreviewSize(int size) 0111 { 0112 m_previewSize = size; 0113 switch (m_previewPosition) { 0114 case Side: 0115 m_iconLabel->setFixedSize(m_previewSize + 8, m_previewSize + 8); 0116 break; 0117 case Below: 0118 m_iconLabel->setFixedSize(3 * m_previewSize + 8, m_previewSize + 8); 0119 break; 0120 } 0121 iconComboChanged(m_icon); 0122 } 0123 0124 int PixmapPreviewSelector::previewSize() const 0125 { 0126 return m_previewSize; 0127 } 0128 0129 void PixmapPreviewSelector::setEditable(bool editable) 0130 { 0131 m_comboItems->setEditable(editable); 0132 m_stampPushButton->setVisible(editable); 0133 } 0134 0135 void PixmapPreviewSelector::iconComboChanged(const QString &icon) 0136 { 0137 int id = m_comboItems->findText(icon, Qt::MatchFixedString); 0138 if (id >= 0) { 0139 m_icon = m_comboItems->itemData(id).toString(); 0140 } else { 0141 m_icon = icon; 0142 } 0143 0144 QPixmap pixmap = Okular::AnnotationUtils::loadStamp(m_icon, m_previewSize); 0145 const QRect cr = m_iconLabel->contentsRect(); 0146 if (pixmap.width() > cr.width() || pixmap.height() > cr.height()) { 0147 pixmap = pixmap.scaled(cr.size(), Qt::KeepAspectRatio, Qt::SmoothTransformation); 0148 } 0149 m_iconLabel->setPixmap(pixmap); 0150 0151 Q_EMIT iconChanged(m_icon); 0152 } 0153 0154 void PixmapPreviewSelector::selectCustomStamp() 0155 { 0156 const QString customStampFile = QFileDialog::getOpenFileName(this, i18nc("@title:window file chooser", "Select custom stamp symbol"), QString(), i18n("*.ico *.png *.xpm *.svg *.svgz | Icon Files (*.ico *.png *.xpm *.svg *.svgz)")); 0157 if (!customStampFile.isEmpty()) { 0158 QPixmap pixmap = Okular::AnnotationUtils::loadStamp(customStampFile, m_previewSize); 0159 if (pixmap.isNull()) { 0160 KMessageBox::error(this, xi18nc("@info", "Could not load the file <filename>%1</filename>", customStampFile), i18nc("@title:window", "Invalid file")); 0161 } else { 0162 m_comboItems->setEditText(customStampFile); 0163 } 0164 } 0165 } 0166 0167 AnnotationWidget *AnnotationWidgetFactory::widgetFor(Okular::Annotation *ann) 0168 { 0169 switch (ann->subType()) { 0170 case Okular::Annotation::AStamp: 0171 return new StampAnnotationWidget(ann); 0172 break; 0173 case Okular::Annotation::AText: 0174 return new TextAnnotationWidget(ann); 0175 break; 0176 case Okular::Annotation::ALine: 0177 return new LineAnnotationWidget(ann); 0178 break; 0179 case Okular::Annotation::AHighlight: 0180 return new HighlightAnnotationWidget(ann); 0181 break; 0182 case Okular::Annotation::AInk: 0183 return new InkAnnotationWidget(ann); 0184 break; 0185 case Okular::Annotation::AGeom: 0186 return new GeomAnnotationWidget(ann); 0187 break; 0188 case Okular::Annotation::AFileAttachment: 0189 return new FileAttachmentAnnotationWidget(ann); 0190 break; 0191 case Okular::Annotation::ACaret: 0192 return new CaretAnnotationWidget(ann); 0193 break; 0194 // shut up gcc 0195 default:; 0196 } 0197 // cases not covered yet: return a generic widget 0198 return new AnnotationWidget(ann); 0199 } 0200 0201 AnnotationWidget::AnnotationWidget(Okular::Annotation *ann) 0202 : m_typeEditable(true) 0203 , m_ann(ann) 0204 { 0205 } 0206 0207 AnnotationWidget::~AnnotationWidget() 0208 { 0209 } 0210 0211 Okular::Annotation::SubType AnnotationWidget::annotationType() const 0212 { 0213 return m_ann->subType(); 0214 } 0215 0216 QWidget *AnnotationWidget::appearanceWidget() 0217 { 0218 if (m_appearanceWidget) { 0219 return m_appearanceWidget; 0220 } 0221 0222 m_appearanceWidget = createAppearanceWidget(); 0223 return m_appearanceWidget; 0224 } 0225 0226 QWidget *AnnotationWidget::extraWidget() 0227 { 0228 if (m_extraWidget) { 0229 return m_extraWidget; 0230 } 0231 0232 m_extraWidget = createExtraWidget(); 0233 return m_extraWidget; 0234 } 0235 0236 void AnnotationWidget::applyChanges() 0237 { 0238 if (m_colorBn) { 0239 m_ann->style().setColor(m_colorBn->color()); 0240 } 0241 if (m_opacity) { 0242 m_ann->style().setOpacity((double)m_opacity->value() / 100.0); 0243 } 0244 } 0245 0246 QWidget *AnnotationWidget::createAppearanceWidget() 0247 { 0248 QWidget *widget = new QWidget(); 0249 QFormLayout *formlayout = new QFormLayout(widget); 0250 formlayout->setLabelAlignment(Qt::AlignRight); 0251 formlayout->setFieldGrowthPolicy(QFormLayout::AllNonFixedFieldsGrow); 0252 0253 createStyleWidget(formlayout); 0254 0255 return widget; 0256 } 0257 0258 void AnnotationWidget::createStyleWidget(QFormLayout *formlayout) 0259 { 0260 Q_UNUSED(formlayout); 0261 } 0262 0263 void AnnotationWidget::addColorButton(QWidget *widget, QFormLayout *formlayout) 0264 { 0265 m_colorBn = new KColorButton(widget); 0266 m_colorBn->setColor(m_ann->style().color()); 0267 formlayout->addRow(i18n("&Color:"), m_colorBn); 0268 connect(m_colorBn, &KColorButton::changed, this, &AnnotationWidget::dataChanged); 0269 } 0270 0271 void AnnotationWidget::addOpacitySpinBox(QWidget *widget, QFormLayout *formlayout) 0272 { 0273 m_opacity = new QSpinBox(widget); 0274 m_opacity->setRange(0, 100); 0275 m_opacity->setValue((int)(m_ann->style().opacity() * 100)); 0276 m_opacity->setSuffix(i18nc("Suffix for the opacity level, eg '80%'", "%")); 0277 formlayout->addRow(i18n("&Opacity:"), m_opacity); 0278 connect(m_opacity, QOverload<int>::of(&QSpinBox::valueChanged), this, &AnnotationWidget::dataChanged); 0279 } 0280 0281 void AnnotationWidget::addVerticalSpacer(QFormLayout *formlayout) 0282 { 0283 formlayout->addItem(new QSpacerItem(0, 5, QSizePolicy::Fixed, QSizePolicy::Fixed)); 0284 } 0285 0286 QWidget *AnnotationWidget::createExtraWidget() 0287 { 0288 return nullptr; 0289 } 0290 0291 TextAnnotationWidget::TextAnnotationWidget(Okular::Annotation *ann) 0292 : AnnotationWidget(ann) 0293 { 0294 m_textAnn = static_cast<Okular::TextAnnotation *>(ann); 0295 } 0296 0297 void TextAnnotationWidget::createStyleWidget(QFormLayout *formlayout) 0298 { 0299 QWidget *widget = qobject_cast<QWidget *>(formlayout->parent()); 0300 0301 if (m_textAnn->textType() == Okular::TextAnnotation::Linked) { 0302 createPopupNoteStyleUi(widget, formlayout); 0303 } else if (m_textAnn->textType() == Okular::TextAnnotation::InPlace) { 0304 if (isTypewriter()) { 0305 createTypewriterStyleUi(widget, formlayout); 0306 } else { 0307 createInlineNoteStyleUi(widget, formlayout); 0308 } 0309 } 0310 } 0311 0312 void TextAnnotationWidget::applyChanges() 0313 { 0314 AnnotationWidget::applyChanges(); 0315 if (m_textAnn->textType() == Okular::TextAnnotation::Linked) { 0316 Q_ASSERT(m_pixmapSelector); 0317 m_textAnn->setTextIcon(m_pixmapSelector->icon()); 0318 } else if (m_textAnn->textType() == Okular::TextAnnotation::InPlace) { 0319 Q_ASSERT(m_fontReq); 0320 m_textAnn->setTextFont(m_fontReq->font()); 0321 if (!isTypewriter()) { 0322 Q_ASSERT(m_textAlign && m_spinWidth); 0323 m_textAnn->setInplaceAlignment(m_textAlign->currentIndex()); 0324 m_textAnn->style().setWidth(m_spinWidth->value()); 0325 } else { 0326 Q_ASSERT(m_textColorBn); 0327 m_textAnn->setTextColor(m_textColorBn->color()); 0328 } 0329 } 0330 } 0331 0332 void AnnotationWidget::setAnnotTypeEditable(bool editable) 0333 { 0334 m_typeEditable = editable; 0335 } 0336 0337 void TextAnnotationWidget::createPopupNoteStyleUi(QWidget *widget, QFormLayout *formlayout) 0338 { 0339 addColorButton(widget, formlayout); 0340 addOpacitySpinBox(widget, formlayout); 0341 addVerticalSpacer(formlayout); 0342 addPixmapSelector(widget, formlayout); 0343 } 0344 0345 void TextAnnotationWidget::createInlineNoteStyleUi(QWidget *widget, QFormLayout *formlayout) 0346 { 0347 addColorButton(widget, formlayout); 0348 addOpacitySpinBox(widget, formlayout); 0349 addVerticalSpacer(formlayout); 0350 addFontRequester(widget, formlayout); 0351 addTextAlignComboBox(widget, formlayout); 0352 addVerticalSpacer(formlayout); 0353 addWidthSpinBox(widget, formlayout); 0354 } 0355 0356 void TextAnnotationWidget::createTypewriterStyleUi(QWidget *widget, QFormLayout *formlayout) 0357 { 0358 addFontRequester(widget, formlayout); 0359 addTextColorButton(widget, formlayout); 0360 } 0361 0362 void TextAnnotationWidget::addPixmapSelector(QWidget *widget, QFormLayout *formlayout) 0363 { 0364 m_pixmapSelector = new PixmapPreviewSelector(widget); 0365 formlayout->addRow(i18n("Icon:"), m_pixmapSelector); 0366 m_pixmapSelector->addItem(i18n("Comment"), QStringLiteral("Comment")); 0367 m_pixmapSelector->addItem(i18n("Help"), QStringLiteral("Help")); 0368 m_pixmapSelector->addItem(i18n("Insert"), QStringLiteral("Insert")); 0369 m_pixmapSelector->addItem(i18n("Key"), QStringLiteral("Key")); 0370 m_pixmapSelector->addItem(i18n("New paragraph"), QStringLiteral("NewParagraph")); 0371 m_pixmapSelector->addItem(i18n("Note"), QStringLiteral("Note")); 0372 m_pixmapSelector->addItem(i18n("Paragraph"), QStringLiteral("Paragraph")); 0373 m_pixmapSelector->setIcon(m_textAnn->textIcon()); 0374 connect(m_pixmapSelector, &PixmapPreviewSelector::iconChanged, this, &AnnotationWidget::dataChanged); 0375 } 0376 0377 void TextAnnotationWidget::addFontRequester(QWidget *widget, QFormLayout *formlayout) 0378 { 0379 m_fontReq = new KFontRequester(widget); 0380 formlayout->addRow(i18n("Font:"), m_fontReq); 0381 m_fontReq->setFont(m_textAnn->textFont()); 0382 connect(m_fontReq, &KFontRequester::fontSelected, this, &AnnotationWidget::dataChanged); 0383 } 0384 0385 void TextAnnotationWidget::addTextColorButton(QWidget *widget, QFormLayout *formlayout) 0386 { 0387 m_textColorBn = new KColorButton(widget); 0388 m_textColorBn->setColor(m_textAnn->textColor()); 0389 formlayout->addRow(i18n("Text &color:"), m_textColorBn); 0390 connect(m_textColorBn, &KColorButton::changed, this, &AnnotationWidget::dataChanged); 0391 } 0392 0393 void TextAnnotationWidget::addTextAlignComboBox(QWidget *widget, QFormLayout *formlayout) 0394 { 0395 m_textAlign = new KComboBox(widget); 0396 formlayout->addRow(i18n("&Align:"), m_textAlign); 0397 m_textAlign->addItem(i18n("Left")); 0398 m_textAlign->addItem(i18n("Center")); 0399 m_textAlign->addItem(i18n("Right")); 0400 m_textAlign->setCurrentIndex(m_textAnn->inplaceAlignment()); 0401 connect(m_textAlign, QOverload<int>::of(&KComboBox::currentIndexChanged), this, &AnnotationWidget::dataChanged); 0402 } 0403 0404 void TextAnnotationWidget::addWidthSpinBox(QWidget *widget, QFormLayout *formlayout) 0405 { 0406 m_spinWidth = new QDoubleSpinBox(widget); 0407 formlayout->addRow(i18n("Border &width:"), m_spinWidth); 0408 m_spinWidth->setRange(0, 100); 0409 m_spinWidth->setValue(m_textAnn->style().width()); 0410 m_spinWidth->setSingleStep(0.1); 0411 connect(m_spinWidth, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, &AnnotationWidget::dataChanged); 0412 } 0413 0414 const QList<QPair<QString, QString>> &StampAnnotationWidget::defaultStamps() 0415 { 0416 static const QList<QPair<QString, QString>> defaultStampsList = {{i18n("Approved"), QStringLiteral("Approved")}, 0417 {i18n("As Is"), QStringLiteral("AsIs")}, 0418 {i18n("Confidential"), QStringLiteral("Confidential")}, 0419 {i18n("Departmental"), QStringLiteral("Departmental")}, 0420 {i18n("Draft"), QStringLiteral("Draft")}, 0421 {i18n("Experimental"), QStringLiteral("Experimental")}, 0422 {i18n("Expired"), QStringLiteral("Expired")}, 0423 {i18n("Final"), QStringLiteral("Final")}, 0424 {i18n("For Comment"), QStringLiteral("ForComment")}, 0425 {i18n("For Public Release"), QStringLiteral("ForPublicRelease")}, 0426 {i18n("Not Approved"), QStringLiteral("NotApproved")}, 0427 {i18n("Not For Public Release"), QStringLiteral("NotForPublicRelease")}, 0428 {i18n("Sold"), QStringLiteral("Sold")}, 0429 {i18n("Top Secret"), QStringLiteral("TopSecret")}, 0430 {i18n("Bookmark"), QStringLiteral("bookmark-new")}, 0431 {i18n("Information"), QStringLiteral("help-about")}, 0432 {i18n("KDE"), QStringLiteral("kde")}, 0433 {i18n("Okular"), QStringLiteral("okular")}}; 0434 0435 return defaultStampsList; 0436 } 0437 0438 StampAnnotationWidget::StampAnnotationWidget(Okular::Annotation *ann) 0439 : AnnotationWidget(ann) 0440 , m_pixmapSelector(nullptr) 0441 { 0442 m_stampAnn = static_cast<Okular::StampAnnotation *>(ann); 0443 } 0444 0445 void StampAnnotationWidget::createStyleWidget(QFormLayout *formlayout) 0446 { 0447 QWidget *widget = qobject_cast<QWidget *>(formlayout->parent()); 0448 0449 addOpacitySpinBox(widget, formlayout); 0450 addVerticalSpacer(formlayout); 0451 0452 m_pixmapSelector = new PixmapPreviewSelector(widget, PixmapPreviewSelector::Below); 0453 formlayout->addRow(i18n("Stamp symbol:"), m_pixmapSelector); 0454 m_pixmapSelector->setEditable(true); 0455 0456 for (const QPair<QString, QString> &pair : defaultStamps()) { 0457 m_pixmapSelector->addItem(pair.first, pair.second); 0458 } 0459 0460 m_pixmapSelector->setIcon(m_stampAnn->stampIconName()); 0461 m_pixmapSelector->setPreviewSize(64); 0462 0463 connect(m_pixmapSelector, &PixmapPreviewSelector::iconChanged, this, &AnnotationWidget::dataChanged); 0464 } 0465 0466 void StampAnnotationWidget::applyChanges() 0467 { 0468 AnnotationWidget::applyChanges(); 0469 m_stampAnn->setStampIconName(m_pixmapSelector->icon()); 0470 } 0471 0472 LineAnnotationWidget::LineAnnotationWidget(Okular::Annotation *ann) 0473 : AnnotationWidget(ann) 0474 { 0475 m_lineAnn = static_cast<Okular::LineAnnotation *>(ann); 0476 if (m_lineAnn->linePoints().count() == 2) { 0477 m_lineType = 0; // line 0478 } else if (m_lineAnn->lineClosed()) { 0479 m_lineType = 1; // polygon 0480 } else { 0481 m_lineType = 2; // polyline 0482 } 0483 } 0484 0485 void LineAnnotationWidget::createStyleWidget(QFormLayout *formlayout) 0486 { 0487 QWidget *widget = qobject_cast<QWidget *>(formlayout->parent()); 0488 0489 addColorButton(widget, formlayout); 0490 addOpacitySpinBox(widget, formlayout); 0491 0492 m_spinSize = new QDoubleSpinBox(widget); 0493 m_spinSize->setRange(1, 100); 0494 m_spinSize->setValue(m_lineAnn->style().width()); 0495 0496 connect(m_spinSize, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, &LineAnnotationWidget::dataChanged); 0497 0498 // Straight line 0499 if (m_lineType == 0) { 0500 addVerticalSpacer(formlayout); 0501 formlayout->addRow(i18n("&Width:"), m_spinSize); 0502 0503 // Line Term Styles 0504 addVerticalSpacer(formlayout); 0505 m_startStyleCombo = new QComboBox(widget); 0506 formlayout->addRow(i18n("Line start:"), m_startStyleCombo); 0507 m_endStyleCombo = new QComboBox(widget); 0508 formlayout->addRow(i18n("Line end:"), m_endStyleCombo); 0509 // FIXME: Where does the tooltip goes?? 0510 0511 const QList<QPair<Okular::LineAnnotation::TermStyle, QString>> termStyles {{Okular::LineAnnotation::Square, i18n("Square")}, 0512 {Okular::LineAnnotation::Circle, i18n("Circle")}, 0513 {Okular::LineAnnotation::Diamond, i18n("Diamond")}, 0514 {Okular::LineAnnotation::OpenArrow, i18n("Open Arrow")}, 0515 {Okular::LineAnnotation::ClosedArrow, i18n("Closed Arrow")}, 0516 {Okular::LineAnnotation::None, i18n("None")}, 0517 {Okular::LineAnnotation::Butt, i18n("Butt")}, 0518 {Okular::LineAnnotation::ROpenArrow, i18n("Right Open Arrow")}, 0519 {Okular::LineAnnotation::RClosedArrow, i18n("Right Closed Arrow")}, 0520 {Okular::LineAnnotation::Slash, i18n("Slash")}}; 0521 for (const auto &item : termStyles) { 0522 const QIcon icon = endStyleIcon(item.first, QGuiApplication::palette().color(QPalette::WindowText)); 0523 m_startStyleCombo->addItem(icon, item.second); 0524 m_endStyleCombo->addItem(icon, item.second); 0525 } 0526 0527 m_startStyleCombo->setCurrentIndex(m_lineAnn->lineStartStyle()); 0528 m_endStyleCombo->setCurrentIndex(m_lineAnn->lineEndStyle()); 0529 0530 // Leaders lengths 0531 addVerticalSpacer(formlayout); 0532 m_spinLL = new QDoubleSpinBox(widget); 0533 formlayout->addRow(i18n("Leader line length:"), m_spinLL); 0534 m_spinLLE = new QDoubleSpinBox(widget); 0535 formlayout->addRow(i18n("Leader line extensions length:"), m_spinLLE); 0536 0537 m_spinLL->setRange(-500, 500); 0538 m_spinLL->setValue(m_lineAnn->lineLeadingForwardPoint()); 0539 m_spinLLE->setRange(0, 500); 0540 m_spinLLE->setValue(m_lineAnn->lineLeadingBackwardPoint()); 0541 0542 connect(m_startStyleCombo, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &LineAnnotationWidget::dataChanged); 0543 connect(m_endStyleCombo, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &LineAnnotationWidget::dataChanged); 0544 connect(m_spinLL, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, &LineAnnotationWidget::dataChanged); 0545 connect(m_spinLLE, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, &LineAnnotationWidget::dataChanged); 0546 } else if (m_lineType == 1) // Polygon 0547 { 0548 QHBoxLayout *colorlay = new QHBoxLayout(); 0549 m_useColor = new QCheckBox(i18n("Enabled"), widget); 0550 colorlay->addWidget(m_useColor); 0551 m_innerColor = new KColorButton(widget); 0552 colorlay->addWidget(m_innerColor); 0553 formlayout->addRow(i18n("Shape fill:"), colorlay); 0554 0555 m_innerColor->setColor(m_lineAnn->lineInnerColor()); 0556 if (m_lineAnn->lineInnerColor().isValid()) { 0557 m_useColor->setChecked(true); 0558 } else { 0559 m_innerColor->setEnabled(false); 0560 } 0561 0562 addVerticalSpacer(formlayout); 0563 formlayout->addRow(i18n("&Width:"), m_spinSize); 0564 0565 connect(m_innerColor, &KColorButton::changed, this, &AnnotationWidget::dataChanged); 0566 connect(m_useColor, &QAbstractButton::toggled, this, &AnnotationWidget::dataChanged); 0567 connect(m_useColor, &QCheckBox::toggled, m_innerColor, &KColorButton::setEnabled); 0568 } 0569 } 0570 0571 void LineAnnotationWidget::applyChanges() 0572 { 0573 AnnotationWidget::applyChanges(); 0574 if (m_lineType == 0) { 0575 Q_ASSERT(m_spinLL && m_spinLLE && m_startStyleCombo && m_endStyleCombo); 0576 m_lineAnn->setLineLeadingForwardPoint(m_spinLL->value()); 0577 m_lineAnn->setLineLeadingBackwardPoint(m_spinLLE->value()); 0578 m_lineAnn->setLineStartStyle((Okular::LineAnnotation::TermStyle)m_startStyleCombo->currentIndex()); 0579 m_lineAnn->setLineEndStyle((Okular::LineAnnotation::TermStyle)m_endStyleCombo->currentIndex()); 0580 } else if (m_lineType == 1) { 0581 Q_ASSERT(m_useColor && m_innerColor); 0582 if (!m_useColor->isChecked()) { 0583 m_lineAnn->setLineInnerColor(QColor()); 0584 } else { 0585 m_lineAnn->setLineInnerColor(m_innerColor->color()); 0586 } 0587 } 0588 Q_ASSERT(m_spinSize); 0589 m_lineAnn->style().setWidth(m_spinSize->value()); 0590 } 0591 0592 QIcon LineAnnotationWidget::endStyleIcon(Okular::LineAnnotation::TermStyle endStyle, const QColor &lineColor) 0593 { 0594 const int iconSize {48}; 0595 QImage image {iconSize, iconSize, QImage::Format_ARGB32}; 0596 image.fill(qRgba(0, 0, 0, 0)); 0597 Okular::LineAnnotation prototype; 0598 prototype.setLinePoints({{0, 0.5}, {0.65, 0.5}}); 0599 prototype.setLineStartStyle(Okular::LineAnnotation::TermStyle::None); 0600 prototype.setLineEndStyle(endStyle); 0601 prototype.style().setWidth(4); 0602 prototype.style().setColor(lineColor); 0603 prototype.style().setLineStyle(Okular::Annotation::LineStyle::Solid); 0604 prototype.setBoundingRectangle({0, 0, 1, 1}); 0605 LineAnnotPainter linepainter {&prototype, QSize {iconSize, iconSize}, 1, QTransform()}; 0606 linepainter.draw(image); 0607 return QIcon(QPixmap::fromImage(image)); 0608 } 0609 0610 InkAnnotationWidget::InkAnnotationWidget(Okular::Annotation *ann) 0611 : AnnotationWidget(ann) 0612 { 0613 m_inkAnn = static_cast<Okular::InkAnnotation *>(ann); 0614 } 0615 0616 void InkAnnotationWidget::createStyleWidget(QFormLayout *formlayout) 0617 { 0618 QWidget *widget = qobject_cast<QWidget *>(formlayout->parent()); 0619 0620 addColorButton(widget, formlayout); 0621 addOpacitySpinBox(widget, formlayout); 0622 0623 addVerticalSpacer(formlayout); 0624 0625 m_spinSize = new QDoubleSpinBox(widget); 0626 formlayout->addRow(i18n("&Width:"), m_spinSize); 0627 0628 m_spinSize->setRange(1, 100); 0629 m_spinSize->setValue(m_inkAnn->style().width()); 0630 0631 connect(m_spinSize, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, &AnnotationWidget::dataChanged); 0632 } 0633 0634 void InkAnnotationWidget::applyChanges() 0635 { 0636 AnnotationWidget::applyChanges(); 0637 m_inkAnn->style().setWidth(m_spinSize->value()); 0638 } 0639 0640 HighlightAnnotationWidget::HighlightAnnotationWidget(Okular::Annotation *ann) 0641 : AnnotationWidget(ann) 0642 { 0643 m_hlAnn = static_cast<Okular::HighlightAnnotation *>(ann); 0644 } 0645 0646 void HighlightAnnotationWidget::createStyleWidget(QFormLayout *formlayout) 0647 { 0648 QWidget *widget = qobject_cast<QWidget *>(formlayout->parent()); 0649 0650 m_typeCombo = new KComboBox(widget); 0651 m_typeCombo->setVisible(m_typeEditable); 0652 if (m_typeEditable) { 0653 formlayout->addRow(i18n("Type:"), m_typeCombo); 0654 } 0655 m_typeCombo->addItem(i18n("Highlight")); 0656 m_typeCombo->addItem(i18n("Squiggle")); 0657 m_typeCombo->addItem(i18n("Underline")); 0658 m_typeCombo->addItem(i18n("Strike out")); 0659 m_typeCombo->setCurrentIndex(m_hlAnn->highlightType()); 0660 0661 addVerticalSpacer(formlayout); 0662 addColorButton(widget, formlayout); 0663 addOpacitySpinBox(widget, formlayout); 0664 0665 connect(m_typeCombo, QOverload<int>::of(&KComboBox::currentIndexChanged), this, &AnnotationWidget::dataChanged); 0666 } 0667 0668 void HighlightAnnotationWidget::applyChanges() 0669 { 0670 AnnotationWidget::applyChanges(); 0671 m_hlAnn->setHighlightType((Okular::HighlightAnnotation::HighlightType)m_typeCombo->currentIndex()); 0672 } 0673 0674 GeomAnnotationWidget::GeomAnnotationWidget(Okular::Annotation *ann) 0675 : AnnotationWidget(ann) 0676 { 0677 m_geomAnn = static_cast<Okular::GeomAnnotation *>(ann); 0678 } 0679 0680 void GeomAnnotationWidget::createStyleWidget(QFormLayout *formlayout) 0681 { 0682 QWidget *widget = qobject_cast<QWidget *>(formlayout->parent()); 0683 0684 m_typeCombo = new KComboBox(widget); 0685 m_typeCombo->setVisible(m_typeEditable); 0686 if (m_typeEditable) { 0687 formlayout->addRow(i18n("Type:"), m_typeCombo); 0688 } 0689 addVerticalSpacer(formlayout); 0690 addColorButton(widget, formlayout); 0691 addOpacitySpinBox(widget, formlayout); 0692 QHBoxLayout *colorlay = new QHBoxLayout(); 0693 m_useColor = new QCheckBox(i18n("Enabled"), widget); 0694 colorlay->addWidget(m_useColor); 0695 m_innerColor = new KColorButton(widget); 0696 colorlay->addWidget(m_innerColor); 0697 formlayout->addRow(i18n("Shape fill:"), colorlay); 0698 addVerticalSpacer(formlayout); 0699 m_spinSize = new QDoubleSpinBox(widget); 0700 formlayout->addRow(i18n("&Width:"), m_spinSize); 0701 0702 m_typeCombo->addItem(i18n("Rectangle")); 0703 m_typeCombo->addItem(i18n("Ellipse")); 0704 m_typeCombo->setCurrentIndex(m_geomAnn->geometricalType()); 0705 m_innerColor->setColor(m_geomAnn->geometricalInnerColor()); 0706 if (m_geomAnn->geometricalInnerColor().isValid()) { 0707 m_useColor->setChecked(true); 0708 } else { 0709 m_innerColor->setEnabled(false); 0710 } 0711 m_spinSize->setRange(0, 100); 0712 m_spinSize->setValue(m_geomAnn->style().width()); 0713 0714 connect(m_typeCombo, QOverload<int>::of(&KComboBox::currentIndexChanged), this, &AnnotationWidget::dataChanged); 0715 connect(m_innerColor, &KColorButton::changed, this, &AnnotationWidget::dataChanged); 0716 connect(m_useColor, &QAbstractButton::toggled, this, &AnnotationWidget::dataChanged); 0717 connect(m_useColor, &QCheckBox::toggled, m_innerColor, &KColorButton::setEnabled); 0718 connect(m_spinSize, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, &AnnotationWidget::dataChanged); 0719 } 0720 0721 void GeomAnnotationWidget::applyChanges() 0722 { 0723 AnnotationWidget::applyChanges(); 0724 m_geomAnn->setGeometricalType((Okular::GeomAnnotation::GeomType)m_typeCombo->currentIndex()); 0725 if (!m_useColor->isChecked()) { 0726 m_geomAnn->setGeometricalInnerColor(QColor()); 0727 } else { 0728 m_geomAnn->setGeometricalInnerColor(m_innerColor->color()); 0729 } 0730 m_geomAnn->style().setWidth(m_spinSize->value()); 0731 } 0732 0733 FileAttachmentAnnotationWidget::FileAttachmentAnnotationWidget(Okular::Annotation *ann) 0734 : AnnotationWidget(ann) 0735 , m_pixmapSelector(nullptr) 0736 { 0737 m_attachAnn = static_cast<Okular::FileAttachmentAnnotation *>(ann); 0738 } 0739 0740 void FileAttachmentAnnotationWidget::createStyleWidget(QFormLayout *formlayout) 0741 { 0742 QWidget *widget = qobject_cast<QWidget *>(formlayout->parent()); 0743 0744 addOpacitySpinBox(widget, formlayout); 0745 0746 m_pixmapSelector = new PixmapPreviewSelector(widget); 0747 formlayout->addRow(i18n("File attachment symbol:"), m_pixmapSelector); 0748 m_pixmapSelector->setEditable(true); 0749 0750 m_pixmapSelector->addItem(i18nc("Symbol for file attachment annotations", "Graph"), QStringLiteral("graph")); 0751 m_pixmapSelector->addItem(i18nc("Symbol for file attachment annotations", "Push Pin"), QStringLiteral("pushpin")); 0752 m_pixmapSelector->addItem(i18nc("Symbol for file attachment annotations", "Paperclip"), QStringLiteral("paperclip")); 0753 m_pixmapSelector->addItem(i18nc("Symbol for file attachment annotations", "Tag"), QStringLiteral("tag")); 0754 m_pixmapSelector->setIcon(m_attachAnn->fileIconName()); 0755 0756 connect(m_pixmapSelector, &PixmapPreviewSelector::iconChanged, this, &AnnotationWidget::dataChanged); 0757 } 0758 0759 QWidget *FileAttachmentAnnotationWidget::createExtraWidget() 0760 { 0761 QWidget *widget = new QWidget(); 0762 widget->setWindowTitle(i18nc("'File' as normal file, that can be opened, saved, etc..", "File")); 0763 0764 Okular::EmbeddedFile *ef = m_attachAnn->embeddedFile(); 0765 const int size = ef->size(); 0766 const QString sizeString = size <= 0 ? i18nc("Not available size", "N/A") : KFormat().formatByteSize(size); 0767 const QString descString = ef->description().isEmpty() ? i18n("No description available.") : ef->description(); 0768 0769 QHBoxLayout *mainLay = new QHBoxLayout(widget); 0770 QFormLayout *lay = new QFormLayout(); 0771 mainLay->addLayout(lay); 0772 0773 QLabel *tmplabel = new QLabel(ef->name(), widget); 0774 tmplabel->setTextInteractionFlags(Qt::TextSelectableByMouse); 0775 lay->addRow(i18n("Name:"), tmplabel); 0776 0777 tmplabel = new QLabel(sizeString, widget); 0778 tmplabel->setTextInteractionFlags(Qt::TextSelectableByMouse); 0779 lay->addRow(i18n("&Width:"), tmplabel); 0780 0781 tmplabel = new QLabel(widget); 0782 tmplabel->setTextFormat(Qt::PlainText); 0783 tmplabel->setWordWrap(true); 0784 tmplabel->setText(descString); 0785 tmplabel->setTextInteractionFlags(Qt::TextSelectableByMouse); 0786 lay->addRow(i18n("Description:"), tmplabel); 0787 0788 QMimeDatabase db; 0789 QMimeType mime = db.mimeTypeForFile(ef->name(), QMimeDatabase::MatchExtension); 0790 if (mime.isValid()) { 0791 tmplabel = new QLabel(widget); 0792 tmplabel->setPixmap(QIcon::fromTheme(mime.iconName()).pixmap(FILEATTACH_ICONSIZE, FILEATTACH_ICONSIZE)); 0793 tmplabel->setFixedSize(FILEATTACH_ICONSIZE, FILEATTACH_ICONSIZE); 0794 QVBoxLayout *tmpLayout = new QVBoxLayout(widget); 0795 tmpLayout->setAlignment(Qt::AlignTop); 0796 mainLay->addLayout(tmpLayout); 0797 tmpLayout->addWidget(tmplabel); 0798 } 0799 0800 return widget; 0801 } 0802 0803 void FileAttachmentAnnotationWidget::applyChanges() 0804 { 0805 AnnotationWidget::applyChanges(); 0806 m_attachAnn->setFileIconName(m_pixmapSelector->icon()); 0807 } 0808 0809 static QString caretSymbolToIcon(Okular::CaretAnnotation::CaretSymbol symbol) 0810 { 0811 switch (symbol) { 0812 case Okular::CaretAnnotation::None: 0813 return QStringLiteral("caret-none"); 0814 case Okular::CaretAnnotation::P: 0815 return QStringLiteral("caret-p"); 0816 } 0817 return QString(); 0818 } 0819 0820 static Okular::CaretAnnotation::CaretSymbol caretSymbolFromIcon(const QString &icon) 0821 { 0822 if (icon == QLatin1String("caret-none")) { 0823 return Okular::CaretAnnotation::None; 0824 } else if (icon == QLatin1String("caret-p")) { 0825 return Okular::CaretAnnotation::P; 0826 } 0827 return Okular::CaretAnnotation::None; 0828 } 0829 0830 CaretAnnotationWidget::CaretAnnotationWidget(Okular::Annotation *ann) 0831 : AnnotationWidget(ann) 0832 , m_pixmapSelector(nullptr) 0833 { 0834 m_caretAnn = static_cast<Okular::CaretAnnotation *>(ann); 0835 } 0836 0837 void CaretAnnotationWidget::createStyleWidget(QFormLayout *formlayout) 0838 { 0839 QWidget *widget = qobject_cast<QWidget *>(formlayout->parent()); 0840 0841 addColorButton(widget, formlayout); 0842 addOpacitySpinBox(widget, formlayout); 0843 0844 m_pixmapSelector = new PixmapPreviewSelector(widget); 0845 formlayout->addRow(i18n("Caret symbol:"), m_pixmapSelector); 0846 0847 m_pixmapSelector->addItem(i18nc("Symbol for caret annotations", "None"), QStringLiteral("caret-none")); 0848 m_pixmapSelector->addItem(i18nc("Symbol for caret annotations", "P"), QStringLiteral("caret-p")); 0849 m_pixmapSelector->setIcon(caretSymbolToIcon(m_caretAnn->caretSymbol())); 0850 0851 connect(m_pixmapSelector, &PixmapPreviewSelector::iconChanged, this, &AnnotationWidget::dataChanged); 0852 } 0853 0854 void CaretAnnotationWidget::applyChanges() 0855 { 0856 AnnotationWidget::applyChanges(); 0857 m_caretAnn->setCaretSymbol(caretSymbolFromIcon(m_pixmapSelector->icon())); 0858 } 0859 0860 #include "moc_annotationwidgets.cpp"