annotationwidgets.cpp 32.8 KB
Newer Older
Pino Toscano's avatar
Pino Toscano committed
1 2 3 4 5 6 7 8 9
/***************************************************************************
 *   Copyright (C) 2006 by Pino Toscano <pino@kde.org>                     *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 ***************************************************************************/

10 11
#include "annotationwidgets.h"

Pino Toscano's avatar
Pino Toscano committed
12
// qt/kde includes
13
#include <qcheckbox.h>
Pino Toscano's avatar
Pino Toscano committed
14 15 16
#include <qgroupbox.h>
#include <qlabel.h>
#include <qlayout.h>
Pino Toscano's avatar
Pino Toscano committed
17
#include <qspinbox.h>
Pino Toscano's avatar
Pino Toscano committed
18
#include <qvariant.h>
19
#include <kcolorbutton.h>
Albert Astals Cid's avatar
Albert Astals Cid committed
20
#include <kcombobox.h>
21
#include <kfontrequester.h>
22 23
#include <KMessageBox>
#include <KMessageWidget>
Laurent Montel's avatar
Laurent Montel committed
24
#include <QIcon>
25
#include <QFileDialog>
Pino Toscano's avatar
Pino Toscano committed
26
#include <kiconloader.h>
Lukáš Tinkl's avatar
Lukáš Tinkl committed
27 28
#include <KLocalizedString>
#include <QDebug>
29 30
#include <QGuiApplication>
#include <QList>
Laurent Montel's avatar
Laurent Montel committed
31
#include <QMimeDatabase>
32
#include <QPair>
33
#include <QSize>
Lukáš Tinkl's avatar
Lukáš Tinkl committed
34
#include <KFormat>
35
#include <QFormLayout>
Pino Toscano's avatar
Pino Toscano committed
36

37
#include "core/document.h"
38
#include "guiutils.h"
39
#include "pagepainter.h"
40

41 42
#define FILEATTACH_ICONSIZE 48

43 44
PixmapPreviewSelector::PixmapPreviewSelector( QWidget * parent, PreviewPosition position )
  : QWidget( parent ), m_previewPosition( position )
45
{
46
    QVBoxLayout * mainlay = new QVBoxLayout( this );
47
    mainlay->setContentsMargins( 0, 0, 0, 0 );
48
    QHBoxLayout * toplay = new QHBoxLayout( this );
49
    toplay->setContentsMargins( 0, 0, 0, 0 );
50
    mainlay->addLayout( toplay );
Albert Astals Cid's avatar
Albert Astals Cid committed
51
    m_comboItems = new KComboBox( this );
52
    toplay->addWidget( m_comboItems );
53
    m_stampPushButton = new QPushButton(QIcon::fromTheme( QStringLiteral("document-open") ), QString(), this );
54 55 56
    m_stampPushButton->setVisible( false );
    m_stampPushButton->setToolTip( i18nc( "@info:tooltip", "Select a custom stamp symbol from file") );
    toplay->addWidget(m_stampPushButton);
57
    m_iconLabel = new QLabel( this );
58 59 60 61 62 63 64 65 66 67
    switch ( m_previewPosition )
    {
        case Side:
            toplay->addWidget( m_iconLabel );
            break;
        case Below:
            mainlay->addWidget( m_iconLabel );
            mainlay->setAlignment( m_iconLabel, Qt::AlignHCenter );
            break;
    }
68 69 70 71 72
    m_iconLabel->setSizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed );
    m_iconLabel->setAlignment( Qt::AlignCenter );
    m_iconLabel->setFrameStyle( QFrame::StyledPanel );
    setPreviewSize( 32 );

73 74 75
    setFocusPolicy( Qt::TabFocus );
    setFocusProxy( m_comboItems );

76
    connect( m_comboItems, QOverload<const QString &>::of(&QComboBox::currentIndexChanged), this, &PixmapPreviewSelector::iconComboChanged );
Laurent Montel's avatar
Laurent Montel committed
77
    connect( m_comboItems, &QComboBox::editTextChanged, this, &PixmapPreviewSelector::iconComboChanged );
78
    connect( m_stampPushButton, &QPushButton::clicked, this, &PixmapPreviewSelector::selectCustomStamp );
79 80 81 82 83 84 85 86
}

PixmapPreviewSelector::~PixmapPreviewSelector()
{
}

void PixmapPreviewSelector::setIcon( const QString& icon )
{
Pino Toscano's avatar
Pino Toscano committed
87
    int id = m_comboItems->findData( QVariant( icon ), Qt::UserRole, Qt::MatchFixedString );
88
    if ( id == -1 )
Pino Toscano's avatar
Pino Toscano committed
89
        id = m_comboItems->findText( icon, Qt::MatchFixedString );
90 91 92 93
    if ( id > -1 )
    {
        m_comboItems->setCurrentIndex( id );
    }
94 95 96 97 98
    else if ( m_comboItems->isEditable() )
    {
        m_comboItems->addItem( icon, QVariant( icon ) );
        m_comboItems->setCurrentIndex( m_comboItems->findText( icon, Qt::MatchFixedString ) );
    }
99 100 101 102 103 104 105
}

QString PixmapPreviewSelector::icon() const
{
    return m_icon;
}

Pino Toscano's avatar
Pino Toscano committed
106
void PixmapPreviewSelector::addItem( const QString& item, const QString& id )
107
{
Pino Toscano's avatar
Pino Toscano committed
108
    m_comboItems->addItem( item, QVariant( id ) );
109 110 111 112 113 114
    setIcon( m_icon );
}

void PixmapPreviewSelector::setPreviewSize( int size )
{
    m_previewSize = size;
115 116 117 118 119 120 121 122 123
    switch( m_previewPosition )
    {
        case Side:
            m_iconLabel->setFixedSize( m_previewSize + 8, m_previewSize + 8 );
            break;
        case Below:
            m_iconLabel->setFixedSize( 3 * m_previewSize + 8, m_previewSize + 8 );
            break;
    }
124 125 126 127 128 129 130 131
    iconComboChanged( m_icon );
}

int PixmapPreviewSelector::previewSize() const
{
    return m_previewSize;
}

132 133 134
void PixmapPreviewSelector::setEditable( bool editable )
{
    m_comboItems->setEditable( editable );
135
    m_stampPushButton->setVisible( editable );
136 137
}

138 139
void PixmapPreviewSelector::iconComboChanged( const QString& icon )
{
Pino Toscano's avatar
Pino Toscano committed
140
    int id = m_comboItems->findText( icon, Qt::MatchFixedString );
141 142 143 144 145 146 147 148
    if ( id >= 0 )
    {
        m_icon = m_comboItems->itemData( id ).toString();
    }
    else
    {
        m_icon = icon;
    }
Pino Toscano's avatar
Pino Toscano committed
149

150
    QPixmap pixmap = GuiUtils::loadStamp( m_icon, m_previewSize );
151 152
    const QRect cr = m_iconLabel->contentsRect();
    if ( pixmap.width() > cr.width() || pixmap.height() > cr.height() )
Pino Toscano's avatar
Pino Toscano committed
153
        pixmap = pixmap.scaled( cr.size(), Qt::KeepAspectRatio, Qt::SmoothTransformation );
154
    m_iconLabel->setPixmap( pixmap );
155 156

    emit iconChanged( m_icon );
157 158
}

159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175
void PixmapPreviewSelector::selectCustomStamp()
{
    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)") );
    if ( !customStampFile.isEmpty() )
    {
        QPixmap pixmap = GuiUtils::loadStamp( customStampFile, m_previewSize );
        if( pixmap.isNull() ) {
            KMessageBox::sorry( this,
                                xi18nc("@info", "Could not load the file <filename>%1</filename>", customStampFile ),
                                i18nc("@title:window", "Invalid file")
                              );
        } else {
            m_comboItems->setEditText(customStampFile);
        }
    }
}
176

177
AnnotationWidget * AnnotationWidgetFactory::widgetFor( Okular::Annotation * ann )
Pino Toscano's avatar
Pino Toscano committed
178 179 180
{
    switch ( ann->subType() )
    {
181
        case Okular::Annotation::AStamp:
Pino Toscano's avatar
Pino Toscano committed
182 183
            return new StampAnnotationWidget( ann );
            break;
184
        case Okular::Annotation::AText:
Pino Toscano's avatar
Pino Toscano committed
185 186
            return new TextAnnotationWidget( ann );
            break;
187
        case Okular::Annotation::ALine:
Pino Toscano's avatar
Pino Toscano committed
188 189
            return new LineAnnotationWidget( ann );
            break;
190 191 192
        case Okular::Annotation::AHighlight:
            return new HighlightAnnotationWidget( ann );
            break;
193 194 195
        case Okular::Annotation::AInk:
            return new InkAnnotationWidget( ann );
            break;
196 197 198
        case Okular::Annotation::AGeom:
            return new GeomAnnotationWidget( ann );
            break;
199 200 201
        case Okular::Annotation::AFileAttachment:
            return new FileAttachmentAnnotationWidget( ann );
            break;
202 203 204
        case Okular::Annotation::ACaret:
            return new CaretAnnotationWidget( ann );
            break;
Pino Toscano's avatar
Pino Toscano committed
205 206 207 208
        // shut up gcc
        default:
            ;
    }
209 210
    // cases not covered yet: return a generic widget
    return new AnnotationWidget( ann );
Pino Toscano's avatar
Pino Toscano committed
211 212 213
}


214
AnnotationWidget::AnnotationWidget( Okular::Annotation * ann )
215
    : m_ann( ann )
Pino Toscano's avatar
Pino Toscano committed
216 217 218 219 220 221 222
{
}

AnnotationWidget::~AnnotationWidget()
{
}

223
Okular::Annotation::SubType AnnotationWidget::annotationType() const
Pino Toscano's avatar
Pino Toscano committed
224 225 226 227
{
    return m_ann->subType();
}

228
QWidget * AnnotationWidget::appearanceWidget()
229
{
230 231
    if ( m_appearanceWidget )
        return m_appearanceWidget;
232

233 234
    m_appearanceWidget = createAppearanceWidget();
    return m_appearanceWidget;
235 236
}

237 238 239 240 241 242 243 244 245
QWidget * AnnotationWidget::extraWidget()
{
    if ( m_extraWidget )
        return m_extraWidget;

    m_extraWidget = createExtraWidget();
    return m_extraWidget;
}

246 247
void AnnotationWidget::applyChanges()
{
248 249 250 251
    if (m_colorBn)
        m_ann->style().setColor( m_colorBn->color() );
    if (m_opacity)
        m_ann->style().setOpacity( (double)m_opacity->value() / 100.0 );
252 253 254 255 256
}

QWidget * AnnotationWidget::createAppearanceWidget()
{
    QWidget * widget = new QWidget();
257 258 259
    QFormLayout * formlayout = new QFormLayout( widget );
    formlayout->setLabelAlignment( Qt::AlignRight );
    formlayout->setFieldGrowthPolicy( QFormLayout::AllNonFixedFieldsGrow );
260

261
    createStyleWidget( formlayout );
262

263 264
    return widget;
}
265

266 267 268 269
void AnnotationWidget::createStyleWidget( QFormLayout * formlayout )
{
    Q_UNUSED( formlayout );
}
270

271 272 273 274 275 276
void AnnotationWidget::addColorButton( QWidget * widget, QFormLayout * formlayout )
{
    m_colorBn = new KColorButton( widget );
    m_colorBn->setColor( m_ann->style().color() );
    formlayout->addRow( i18n( "&Color:" ), m_colorBn );
    connect( m_colorBn, &KColorButton::changed, this, &AnnotationWidget::dataChanged );
277 278
}

279
void AnnotationWidget::addOpacitySpinBox( QWidget * widget, QFormLayout * formlayout )
280
{
281 282 283 284 285
    m_opacity = new QSpinBox( widget );
    m_opacity->setRange( 0, 100 );
    m_opacity->setValue( (int)( m_ann->style().opacity() * 100 ) );
    m_opacity->setSuffix( i18nc( "Suffix for the opacity level, eg '80 %'", " %" ) );
    formlayout->addRow( i18n( "&Opacity:" ), m_opacity);
286
    connect( m_opacity, QOverload<int>::of(&QSpinBox::valueChanged), this, &AnnotationWidget::dataChanged );
287 288 289 290 291
}

void AnnotationWidget::addVerticalSpacer( QFormLayout * formlayout )
{
    formlayout->addItem( new QSpacerItem( 0, 5, QSizePolicy::Fixed, QSizePolicy::Fixed ) );
292 293
}

294 295
QWidget * AnnotationWidget::createExtraWidget()
{
296
    return nullptr;
297 298
}

Pino Toscano's avatar
Pino Toscano committed
299

300
TextAnnotationWidget::TextAnnotationWidget( Okular::Annotation * ann )
301
    : AnnotationWidget( ann )
Pino Toscano's avatar
Pino Toscano committed
302
{
303
    m_textAnn = static_cast< Okular::TextAnnotation * >( ann );
Pino Toscano's avatar
Pino Toscano committed
304 305
}

306
void TextAnnotationWidget::createStyleWidget( QFormLayout * formlayout )
Pino Toscano's avatar
Pino Toscano committed
307
{
308
    QWidget * widget = qobject_cast<QWidget *>( formlayout->parent() );
309 310 311

    if ( m_textAnn->textType() == Okular::TextAnnotation::Linked )
    {
312
        createPopupNoteStyleUi( widget, formlayout );
313 314 315
    }
    else if ( m_textAnn->textType() == Okular::TextAnnotation::InPlace )
    {
316
        if ( isTypewriter() )
317
            createTypewriterStyleUi( widget, formlayout );
318
        else
319
            createInlineNoteStyleUi( widget, formlayout );
320
    }
321 322
}

Pino Toscano's avatar
Pino Toscano committed
323 324
void TextAnnotationWidget::applyChanges()
{
325
    AnnotationWidget::applyChanges();
326
    if ( m_textAnn->textType() == Okular::TextAnnotation::Linked )
Pino Toscano's avatar
Pino Toscano committed
327
    {
328
        Q_ASSERT( m_pixmapSelector );
329
        m_textAnn->setTextIcon( m_pixmapSelector->icon() );
Pino Toscano's avatar
Pino Toscano committed
330
    }
331 332
    else if ( m_textAnn->textType() == Okular::TextAnnotation::InPlace )
    {
333
        Q_ASSERT( m_fontReq );
334
        m_textAnn->setTextFont( m_fontReq->font() );
335 336
        if ( !isTypewriter() )
        {
337
            Q_ASSERT( m_textAlign && m_spinWidth );
338 339 340
            m_textAnn->setInplaceAlignment( m_textAlign->currentIndex() );
            m_textAnn->style().setWidth( m_spinWidth->value() );
        }
341 342 343 344 345
        else
        {
            Q_ASSERT( m_textColorBn );
            m_textAnn->setTextColor( m_textColorBn->color() );
        }
346
    }
Pino Toscano's avatar
Pino Toscano committed
347 348
}

349 350 351 352 353
void TextAnnotationWidget::createPopupNoteStyleUi( QWidget * widget, QFormLayout * formlayout  ) {
    addColorButton( widget, formlayout );
    addOpacitySpinBox( widget, formlayout );
    addVerticalSpacer( formlayout );
    addPixmapSelector( widget, formlayout );
354 355
}

356 357 358 359 360 361 362 363
void TextAnnotationWidget::createInlineNoteStyleUi( QWidget * widget, QFormLayout * formlayout  ) {
    addColorButton( widget, formlayout );
    addOpacitySpinBox( widget, formlayout );
    addVerticalSpacer( formlayout );
    addFontRequester( widget, formlayout );
    addTextAlignComboBox( widget, formlayout );
    addVerticalSpacer( formlayout );
    addWidthSpinBox( widget, formlayout );
364 365
}

366 367 368
void TextAnnotationWidget::createTypewriterStyleUi( QWidget * widget, QFormLayout * formlayout  ) {
    addFontRequester( widget, formlayout );
    addTextColorButton( widget, formlayout );
369 370
}

371
void TextAnnotationWidget::addPixmapSelector( QWidget * widget, QFormLayout * formlayout )
372
{
373 374 375 376 377 378 379 380 381 382 383
    m_pixmapSelector = new PixmapPreviewSelector( widget );
    formlayout->addRow( i18n( "Icon:" ), m_pixmapSelector );
    m_pixmapSelector->addItem( i18n( "Comment" ), QStringLiteral("Comment") );
    m_pixmapSelector->addItem( i18n( "Help" ), QStringLiteral("Help") );
    m_pixmapSelector->addItem( i18n( "Insert" ), QStringLiteral("Insert") );
    m_pixmapSelector->addItem( i18n( "Key" ), QStringLiteral("Key") );
    m_pixmapSelector->addItem( i18n( "New paragraph" ), QStringLiteral("NewParagraph") );
    m_pixmapSelector->addItem( i18n( "Note" ), QStringLiteral("Note") );
    m_pixmapSelector->addItem( i18n( "Paragraph" ), QStringLiteral("Paragraph") );
    m_pixmapSelector->setIcon( m_textAnn->textIcon() );
    connect( m_pixmapSelector, &PixmapPreviewSelector::iconChanged, this, &AnnotationWidget::dataChanged );
384 385
}

386
void TextAnnotationWidget::addFontRequester( QWidget * widget, QFormLayout * formlayout )
387 388
{
    m_fontReq = new KFontRequester( widget );
389
    formlayout->addRow( i18n( "Font:" ), m_fontReq );
390 391 392 393
    m_fontReq->setFont( m_textAnn->textFont() );
    connect( m_fontReq, &KFontRequester::fontSelected, this, &AnnotationWidget::dataChanged );
}

394
void TextAnnotationWidget::addTextColorButton( QWidget * widget, QFormLayout * formlayout )
395 396 397
{
    m_textColorBn = new KColorButton( widget );
    m_textColorBn->setColor( m_textAnn->textColor() );
398
    formlayout->addRow( i18n( "Text &color:" ), m_textColorBn );
399 400 401
    connect( m_textColorBn, &KColorButton::changed, this, &AnnotationWidget::dataChanged );
}

402
void TextAnnotationWidget::addTextAlignComboBox( QWidget * widget, QFormLayout * formlayout )
403
{
404

405
    m_textAlign = new KComboBox( widget );
406
    formlayout->addRow( i18n( "&Align:" ), m_textAlign );
407 408 409 410
    m_textAlign->addItem( i18n("Left") );
    m_textAlign->addItem( i18n("Center") );
    m_textAlign->addItem( i18n("Right") );
    m_textAlign->setCurrentIndex( m_textAnn->inplaceAlignment() );
411
    connect( m_textAlign, QOverload<int>::of(&KComboBox::currentIndexChanged), this, &AnnotationWidget::dataChanged );
412 413
}

414
void TextAnnotationWidget::addWidthSpinBox( QWidget * widget, QFormLayout * formlayout )
415 416
{
    m_spinWidth = new QDoubleSpinBox( widget );
417
    formlayout->addRow( i18n( "Border &width:" ), m_spinWidth );
418 419 420
    m_spinWidth->setRange( 0, 100 );
    m_spinWidth->setValue( m_textAnn->style().width() );
    m_spinWidth->setSingleStep( 0.1 );
421
    connect( m_spinWidth, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, &AnnotationWidget::dataChanged );
422
}
Pino Toscano's avatar
Pino Toscano committed
423

424
StampAnnotationWidget::StampAnnotationWidget( Okular::Annotation * ann )
425
    : AnnotationWidget( ann ), m_pixmapSelector( nullptr )
Pino Toscano's avatar
Pino Toscano committed
426
{
427
    m_stampAnn = static_cast< Okular::StampAnnotation * >( ann );
Pino Toscano's avatar
Pino Toscano committed
428 429
}

430
void StampAnnotationWidget::createStyleWidget( QFormLayout * formlayout )
Pino Toscano's avatar
Pino Toscano committed
431
{
432 433
    QWidget * widget = qobject_cast<QWidget *>( formlayout->parent() );

434 435 436 437 438 439 440 441
    KMessageWidget * brokenStampSupportWarning = new KMessageWidget( widget );
    brokenStampSupportWarning->setText( xi18nc("@info", "<warning>experimental feature.<nl/>"
                                                        "Stamps inserted in PDF documents are not visible in PDF readers other than Okular.</warning>") );
    brokenStampSupportWarning->setMessageType( KMessageWidget::Warning );
    brokenStampSupportWarning->setWordWrap( true );
    brokenStampSupportWarning->setCloseButtonVisible( false );
    formlayout->insertRow( 0, brokenStampSupportWarning );

442 443 444
    addOpacitySpinBox( widget, formlayout );
    addVerticalSpacer( formlayout );

445
    m_pixmapSelector = new PixmapPreviewSelector( widget, PixmapPreviewSelector::Below );
446
    formlayout->addRow( i18n( "Stamp symbol:" ), m_pixmapSelector );
447
    m_pixmapSelector->setEditable( true );
Pino Toscano's avatar
Pino Toscano committed
448

Laurent Montel's avatar
Laurent Montel committed
449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466
    m_pixmapSelector->addItem( i18n( "Okular" ), QStringLiteral("okular") );
    m_pixmapSelector->addItem( i18n( "Bookmark" ), QStringLiteral("bookmarks") );
    m_pixmapSelector->addItem( i18n( "KDE" ), QStringLiteral("kde") );
    m_pixmapSelector->addItem( i18n( "Information" ), QStringLiteral("help-about") );
    m_pixmapSelector->addItem( i18n( "Approved" ), QStringLiteral("Approved") );
    m_pixmapSelector->addItem( i18n( "As Is" ), QStringLiteral("AsIs") );
    m_pixmapSelector->addItem( i18n( "Confidential" ), QStringLiteral("Confidential") );
    m_pixmapSelector->addItem( i18n( "Departmental" ), QStringLiteral("Departmental") );
    m_pixmapSelector->addItem( i18n( "Draft" ), QStringLiteral("Draft") );
    m_pixmapSelector->addItem( i18n( "Experimental" ), QStringLiteral("Experimental") );
    m_pixmapSelector->addItem( i18n( "Expired" ), QStringLiteral("Expired") );
    m_pixmapSelector->addItem( i18n( "Final" ), QStringLiteral("Final") );
    m_pixmapSelector->addItem( i18n( "For Comment" ), QStringLiteral("ForComment") );
    m_pixmapSelector->addItem( i18n( "For Public Release" ), QStringLiteral("ForPublicRelease") );
    m_pixmapSelector->addItem( i18n( "Not Approved" ), QStringLiteral("NotApproved") );
    m_pixmapSelector->addItem( i18n( "Not For Public Release" ), QStringLiteral("NotForPublicRelease") );
    m_pixmapSelector->addItem( i18n( "Sold" ), QStringLiteral("Sold") );
    m_pixmapSelector->addItem( i18n( "Top Secret" ), QStringLiteral("TopSecret") );
467
    m_pixmapSelector->setIcon( m_stampAnn->stampIconName() );
468
    m_pixmapSelector->setPreviewSize( 64 );
Pino Toscano's avatar
Pino Toscano committed
469

Laurent Montel's avatar
Laurent Montel committed
470
    connect( m_pixmapSelector, &PixmapPreviewSelector::iconChanged, this, &AnnotationWidget::dataChanged );
Pino Toscano's avatar
Pino Toscano committed
471 472 473 474
}

void StampAnnotationWidget::applyChanges()
{
475
    AnnotationWidget::applyChanges();
476
    m_stampAnn->setStampIconName( m_pixmapSelector->icon() );
Pino Toscano's avatar
Pino Toscano committed
477 478 479 480
}



481
LineAnnotationWidget::LineAnnotationWidget( Okular::Annotation * ann )
482
    : AnnotationWidget( ann )
Pino Toscano's avatar
Pino Toscano committed
483
{
484
    m_lineAnn = static_cast< Okular::LineAnnotation * >( ann );
485
    if ( m_lineAnn->linePoints().count() == 2 )
Pino Toscano's avatar
Pino Toscano committed
486
        m_lineType = 0; // line
487
    else if ( m_lineAnn->lineClosed() )
Pino Toscano's avatar
Pino Toscano committed
488 489 490 491 492
        m_lineType = 1; // polygon
    else
        m_lineType = 2; // polyline
}

493
void LineAnnotationWidget::createStyleWidget( QFormLayout * formlayout )
Pino Toscano's avatar
Pino Toscano committed
494
{
495
    QWidget * widget = qobject_cast<QWidget *>( formlayout->parent() );
496

497 498 499 500 501 502 503 504
    addColorButton( widget, formlayout );
    addOpacitySpinBox( widget, formlayout );

    m_spinSize = new QDoubleSpinBox( widget );
    m_spinSize->setRange( 1, 100 );
    m_spinSize->setValue( m_lineAnn->style().width() );

    connect( m_spinSize, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, &LineAnnotationWidget::dataChanged );
505

506 507
    // Straight line
    if ( m_lineType == 0 )
508
    {
509 510
        addVerticalSpacer( formlayout );
        formlayout->addRow( i18n( "&Width:" ), m_spinSize );
511 512

        //Line Term Styles
513
        addVerticalSpacer( formlayout );
514
        m_startStyleCombo = new QComboBox( widget );
515
        formlayout->addRow( i18n( "Line start:" ), m_startStyleCombo);
516
        m_endStyleCombo = new QComboBox( widget );
517 518
        formlayout->addRow( i18n( "Line end:" ), m_endStyleCombo);
        //FIXME: Where does the tooltip goes??
519

520
        const QList<QPair<Okular::LineAnnotation::TermStyle, QString>> termStyles
521
        {
522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537
            { Okular::LineAnnotation::Square, i18n( "Square" ) },
            { Okular::LineAnnotation::Circle, i18n( "Circle" ) },
            { Okular::LineAnnotation::Diamond, i18n( "Diamond" ) },
            { Okular::LineAnnotation::OpenArrow, i18n( "Open Arrow" ) },
            { Okular::LineAnnotation::ClosedArrow, i18n( "Closed Arrow" ) },
            { Okular::LineAnnotation::None, i18n( "None" ) },
            { Okular::LineAnnotation::Butt, i18n( "Butt" ) },
            { Okular::LineAnnotation::ROpenArrow, i18n( "Right Open Arrow" ) },
            { Okular::LineAnnotation::RClosedArrow, i18n( "Right Closed Arrow" ) },
            { Okular::LineAnnotation::Slash, i18n( "Slash" ) }
        };
        for ( const auto &item: termStyles )
        {
            const QIcon icon = endStyleIcon( item.first, QGuiApplication::palette().color( QPalette::WindowText ) );
            m_startStyleCombo->addItem( icon, item.second );
            m_endStyleCombo->addItem( icon, item.second );
538 539 540 541 542
        }

        m_startStyleCombo->setCurrentIndex( m_lineAnn->lineStartStyle() );
        m_endStyleCombo->setCurrentIndex( m_lineAnn->lineEndStyle() );

543 544 545 546 547 548
        //Leaders lengths
        addVerticalSpacer( formlayout );
        m_spinLL = new QDoubleSpinBox( widget );
        formlayout->addRow( i18n( "Leader line length:" ), m_spinLL );
        m_spinLLE = new QDoubleSpinBox( widget );
        formlayout->addRow( i18n( "Leader line extensions length:" ), m_spinLLE );
549

550 551 552 553
        m_spinLL->setRange( -500, 500 );
        m_spinLL->setValue( m_lineAnn->lineLeadingForwardPoint() );
        m_spinLLE->setRange( 0, 500 );
        m_spinLLE->setValue( m_lineAnn->lineLeadingBackwardPoint() );
Pino Toscano's avatar
Pino Toscano committed
554

555 556
        connect( m_startStyleCombo, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &LineAnnotationWidget::dataChanged );
        connect( m_endStyleCombo, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &LineAnnotationWidget::dataChanged );
557 558
        connect( m_spinLL, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, &LineAnnotationWidget::dataChanged );
        connect( m_spinLLE, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, &LineAnnotationWidget::dataChanged );
559
    }
560
    else if ( m_lineType == 1 ) // Polygon
561
    {
562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581
        QHBoxLayout * colorlay = new QHBoxLayout();
        m_useColor = new QCheckBox( i18n( "Enabled" ), widget );
        colorlay->addWidget( m_useColor );
        m_innerColor = new KColorButton( widget );
        colorlay->addWidget( m_innerColor);
        formlayout->addRow( i18n( "Shape fill:" ), colorlay );

        m_innerColor->setColor( m_lineAnn->lineInnerColor() );
        if ( m_lineAnn->lineInnerColor().isValid() )
        {
            m_useColor->setChecked( true );
        }
        else
        {
            m_innerColor->setEnabled( false );
        }

        addVerticalSpacer( formlayout );
        formlayout->addRow( i18n( "&Width:" ), m_spinSize );

Laurent Montel's avatar
Laurent Montel committed
582 583
        connect( m_innerColor, &KColorButton::changed, this, &AnnotationWidget::dataChanged );
        connect( m_useColor, &QAbstractButton::toggled, this, &AnnotationWidget::dataChanged );
584
        connect( m_useColor, &QCheckBox::toggled, m_innerColor, &KColorButton::setEnabled );
585
    }
Pino Toscano's avatar
Pino Toscano committed
586 587 588 589
}

void LineAnnotationWidget::applyChanges()
{
590
    AnnotationWidget::applyChanges();
Pino Toscano's avatar
Pino Toscano committed
591 592
    if ( m_lineType == 0 )
    {
593
        Q_ASSERT(m_spinLL && m_spinLLE && m_startStyleCombo && m_endStyleCombo);
594 595
        m_lineAnn->setLineLeadingForwardPoint( m_spinLL->value() );
        m_lineAnn->setLineLeadingBackwardPoint( m_spinLLE->value() );
596 597
        m_lineAnn->setLineStartStyle( (Okular::LineAnnotation::TermStyle)m_startStyleCombo->currentIndex() );
        m_lineAnn->setLineEndStyle( (Okular::LineAnnotation::TermStyle)m_endStyleCombo->currentIndex() );
Pino Toscano's avatar
Pino Toscano committed
598
    }
599 600
    else if ( m_lineType == 1 )
    {
601
        Q_ASSERT( m_useColor && m_innerColor );
602 603 604 605 606 607 608 609 610
        if ( !m_useColor->isChecked() )
        {
            m_lineAnn->setLineInnerColor( QColor() );
        }
        else
        {
            m_lineAnn->setLineInnerColor( m_innerColor->color() );
        }
    }
611
    Q_ASSERT( m_spinSize );
612
    m_lineAnn->style().setWidth( m_spinSize->value() );
Pino Toscano's avatar
Pino Toscano committed
613 614
}

615 616 617 618 619 620 621 622 623 624 625 626
QIcon LineAnnotationWidget::endStyleIcon( Okular::LineAnnotation::TermStyle endStyle, const QColor &lineColor ) {
    const int iconSize { 48 };
    QImage image { iconSize, iconSize, QImage::Format_ARGB32};
    image.fill( qRgba(0, 0, 0, 0) );
    Okular::LineAnnotation prototype;
    prototype.setLinePoints( { { 0, 0.5 }, { 0.65, 0.5 } } );
    prototype.setLineStartStyle(Okular::LineAnnotation::TermStyle::None);
    prototype.setLineEndStyle( endStyle );
    prototype.style().setWidth( 4 );
    prototype.style().setColor( lineColor );
    prototype.style().setLineStyle( Okular::Annotation::LineStyle::Solid );
    prototype.setBoundingRectangle( { 0, 0, 1, 1 } );
627
    LineAnnotPainter linepainter { &prototype, QSize { iconSize, iconSize }, 1, QTransform() };
628 629 630 631
    linepainter.draw( image );
    return QIcon( QPixmap::fromImage( image ) );
}

Pino Toscano's avatar
Pino Toscano committed
632 633


634 635 636 637 638 639
InkAnnotationWidget::InkAnnotationWidget( Okular::Annotation * ann )
    : AnnotationWidget( ann )
{
    m_inkAnn = static_cast< Okular::InkAnnotation * >( ann );
}

640
void InkAnnotationWidget::createStyleWidget( QFormLayout * formlayout )
641
{
642 643 644 645 646 647 648 649 650
    QWidget * widget = qobject_cast<QWidget *>( formlayout->parent() );

    addColorButton( widget, formlayout );
    addOpacitySpinBox( widget, formlayout );

    addVerticalSpacer( formlayout );

    m_spinSize = new QDoubleSpinBox( widget );
    formlayout->addRow( i18n( "&Width:" ), m_spinSize );
651 652 653 654

    m_spinSize->setRange( 1, 100 );
    m_spinSize->setValue( m_inkAnn->style().width() );

655
    connect( m_spinSize, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, &AnnotationWidget::dataChanged );
656 657 658 659 660 661 662 663 664 665
}

void InkAnnotationWidget::applyChanges()
{
    AnnotationWidget::applyChanges();
    m_inkAnn->style().setWidth( m_spinSize->value() );
}



666
HighlightAnnotationWidget::HighlightAnnotationWidget( Okular::Annotation * ann )
667
    : AnnotationWidget( ann )
668 669 670 671
{
    m_hlAnn = static_cast< Okular::HighlightAnnotation * >( ann );
}

672
void HighlightAnnotationWidget::createStyleWidget( QFormLayout * formlayout )
673
{
674
    QWidget * widget = qobject_cast<QWidget *>( formlayout->parent() );
675

676 677
    m_typeCombo = new KComboBox( widget );
    formlayout->addRow( i18n( "Type:" ), m_typeCombo );
678
    m_typeCombo->addItem( i18n( "Highlight" ) );
679
    m_typeCombo->addItem( i18n( "Squiggle" ) );
680
    m_typeCombo->addItem( i18n( "Underline" ) );
Pino Toscano's avatar
Pino Toscano committed
681
    m_typeCombo->addItem( i18n( "Strike out" ) );
682
    m_typeCombo->setCurrentIndex( m_hlAnn->highlightType() );
683

684 685 686
    addVerticalSpacer( formlayout );
    addColorButton( widget, formlayout );
    addOpacitySpinBox( widget, formlayout );
687

688
    connect( m_typeCombo, QOverload<int>::of(&KComboBox::currentIndexChanged), this, &AnnotationWidget::dataChanged );
689 690 691 692
}

void HighlightAnnotationWidget::applyChanges()
{
693
    AnnotationWidget::applyChanges();
694
    m_hlAnn->setHighlightType( (Okular::HighlightAnnotation::HighlightType)m_typeCombo->currentIndex() );
695 696 697 698
}



699
GeomAnnotationWidget::GeomAnnotationWidget( Okular::Annotation * ann )
700
    : AnnotationWidget( ann )
701 702 703 704
{
    m_geomAnn = static_cast< Okular::GeomAnnotation * >( ann );
}

705
void GeomAnnotationWidget::createStyleWidget( QFormLayout * formlayout )
706
{
707 708
    QWidget * widget = qobject_cast<QWidget *>( formlayout->parent() );

709
    m_typeCombo = new KComboBox( widget );
710 711 712 713 714 715 716
    formlayout->addRow( i18n( "Type:" ), m_typeCombo );
    addVerticalSpacer( formlayout );
    addColorButton( widget, formlayout );
    addOpacitySpinBox( widget, formlayout );
    QHBoxLayout * colorlay = new QHBoxLayout();
    m_useColor = new QCheckBox( i18n( "Enabled" ), widget );
    colorlay->addWidget(m_useColor);
717
    m_innerColor = new KColorButton( widget );
718 719 720
    colorlay->addWidget( m_innerColor);
    formlayout->addRow( i18n( "Shape fill:" ), colorlay );
    addVerticalSpacer( formlayout );
721
    m_spinSize = new QDoubleSpinBox( widget );
722
    formlayout->addRow( i18n( "&Width:" ), m_spinSize );
723 724 725

    m_typeCombo->addItem( i18n( "Rectangle" ) );
    m_typeCombo->addItem( i18n( "Ellipse" ) );
726 727 728
    m_typeCombo->setCurrentIndex( m_geomAnn->geometricalType() );
    m_innerColor->setColor( m_geomAnn->geometricalInnerColor() );
    if ( m_geomAnn->geometricalInnerColor().isValid() )
729 730 731 732 733 734 735
    {
        m_useColor->setChecked( true );
    }
    else
    {
        m_innerColor->setEnabled( false );
    }
736
    m_spinSize->setRange( 0, 100 );
737
    m_spinSize->setValue( m_geomAnn->style().width() );
738

739
    connect( m_typeCombo, QOverload<int>::of(&KComboBox::currentIndexChanged), this, &AnnotationWidget::dataChanged );
Laurent Montel's avatar
Laurent Montel committed
740 741
    connect( m_innerColor, &KColorButton::changed, this, &AnnotationWidget::dataChanged );
    connect( m_useColor, &QAbstractButton::toggled, this, &AnnotationWidget::dataChanged );
Laurent Montel's avatar
Laurent Montel committed
742
    connect(m_useColor, &QCheckBox::toggled, m_innerColor, &KColorButton::setEnabled);
743
    connect( m_spinSize, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, &AnnotationWidget::dataChanged );
744 745 746 747
}

void GeomAnnotationWidget::applyChanges()
{
748
    AnnotationWidget::applyChanges();
749
    m_geomAnn->setGeometricalType( (Okular::GeomAnnotation::GeomType)m_typeCombo->currentIndex() );
750 751
    if ( !m_useColor->isChecked() )
    {
752
        m_geomAnn->setGeometricalInnerColor( QColor() );
753 754 755
    }
    else
    {
756
        m_geomAnn->setGeometricalInnerColor( m_innerColor->color() );
757
    }
758
    m_geomAnn->style().setWidth( m_spinSize->value() );
759 760
}

761 762 763


FileAttachmentAnnotationWidget::FileAttachmentAnnotationWidget( Okular::Annotation * ann )
764
    : AnnotationWidget( ann ), m_pixmapSelector( nullptr )
765 766 767 768
{
    m_attachAnn = static_cast< Okular::FileAttachmentAnnotation * >( ann );
}

769
void FileAttachmentAnnotationWidget::createStyleWidget( QFormLayout * formlayout )
770
{
771 772 773 774 775 776
    QWidget * widget = qobject_cast<QWidget *>( formlayout->parent() );

    addOpacitySpinBox( widget, formlayout );

    m_pixmapSelector = new PixmapPreviewSelector( widget );
    formlayout->addRow( i18n( "File attachment symbol:" ), m_pixmapSelector );
777 778
    m_pixmapSelector->setEditable( true );

Laurent Montel's avatar
Laurent Montel committed
779 780 781 782
    m_pixmapSelector->addItem( i18nc( "Symbol for file attachment annotations", "Graph" ), QStringLiteral("graph") );
    m_pixmapSelector->addItem( i18nc( "Symbol for file attachment annotations", "Push Pin" ), QStringLiteral("pushpin") );
    m_pixmapSelector->addItem( i18nc( "Symbol for file attachment annotations", "Paperclip" ), QStringLiteral("paperclip") );
    m_pixmapSelector->addItem( i18nc( "Symbol for file attachment annotations", "Tag" ), QStringLiteral("tag") );
783 784
    m_pixmapSelector->setIcon( m_attachAnn->fileIconName() );

Laurent Montel's avatar
Laurent Montel committed
785
    connect( m_pixmapSelector, &PixmapPreviewSelector::iconChanged, this, &AnnotationWidget::dataChanged );
786 787 788 789 790 791 792 793 794
}

QWidget * FileAttachmentAnnotationWidget::createExtraWidget()
{
    QWidget * widget = new QWidget();
    widget->setWindowTitle( i18nc( "'File' as normal file, that can be opened, saved, etc..", "File" ) );

    Okular::EmbeddedFile *ef = m_attachAnn->embeddedFile();
    const int size = ef->size();
795
    const QString sizeString = size <= 0 ? i18nc( "Not available size", "N/A" ) : KFormat().formatByteSize( size );
796
    const QString descString = ef->description().isEmpty() ? i18n( "No description available." ) : ef->description();
797

798 799 800 801 802
    QHBoxLayout * mainLay = new QHBoxLayout( widget );
    QFormLayout * lay = new QFormLayout();
    mainLay->addLayout( lay );

    QLabel * tmplabel = new QLabel( ef->name() , widget );
803
    tmplabel->setTextInteractionFlags( Qt::TextSelectableByMouse );
804
    lay->addRow( i18n( "Name:" ), tmplabel );
805

806
    tmplabel = new QLabel( sizeString, widget );
807
    tmplabel->setTextInteractionFlags( Qt::TextSelectableByMouse );
808
    lay->addRow( i18n( "&Width:" ), tmplabel );
809

810 811 812 813
    tmplabel = new QLabel( widget );
    tmplabel->setTextFormat( Qt::PlainText );
    tmplabel->setWordWrap( true );
    tmplabel->setText( descString );
814
    tmplabel->setTextInteractionFlags( Qt::TextSelectableByMouse );
815
    lay->addRow( i18n( "Description:" ), tmplabel );
816

Frederik Gladhorn's avatar
Frederik Gladhorn committed
817 818 819
    QMimeDatabase db;
    QMimeType mime = db.mimeTypeForFile( ef->name(), QMimeDatabase::MatchExtension);
    if ( mime.isValid() )
820 821
    {
        tmplabel = new QLabel( widget );
Frederik Gladhorn's avatar
Frederik Gladhorn committed
822
        tmplabel->setPixmap( QIcon::fromTheme( mime.iconName() ).pixmap( FILEATTACH_ICONSIZE, FILEATTACH_ICONSIZE ) );
823
        tmplabel->setFixedSize( FILEATTACH_ICONSIZE, FILEATTACH_ICONSIZE );
824 825 826 827
        QVBoxLayout * tmpLayout = new QVBoxLayout( widget );
        tmpLayout->setAlignment( Qt::AlignTop );
        mainLay->addLayout( tmpLayout );
        tmpLayout->addWidget( tmplabel );
828 829 830 831 832 833 834
    }

    return widget;
}

void FileAttachmentAnnotationWidget::applyChanges()
{
835
    AnnotationWidget::applyChanges();
836
    m_attachAnn->setFileIconName( m_pixmapSelector->icon() );
837 838 839
}


840 841 842 843 844 845

static QString caretSymbolToIcon( Okular::CaretAnnotation::CaretSymbol symbol )
{
    switch ( symbol )
    {
        case Okular::CaretAnnotation::None:
Laurent Montel's avatar
Laurent Montel committed
846
            return QStringLiteral( "caret-none" );
847
        case Okular::CaretAnnotation::P:
Laurent Montel's avatar
Laurent Montel committed
848
            return QStringLiteral( "caret-p" );
849 850 851 852 853 854 855 856 857 858 859 860 861 862
    }
    return QString();
}

static Okular::CaretAnnotation::CaretSymbol caretSymbolFromIcon( const QString &icon )
{
    if ( icon == QLatin1String( "caret-none" ) )
        return Okular::CaretAnnotation::None;
    else if ( icon == QLatin1String( "caret-p" ) )
        return Okular::CaretAnnotation::P;
    return Okular::CaretAnnotation::None;
}

CaretAnnotationWidget::CaretAnnotationWidget( Okular::Annotation * ann )
863
    : AnnotationWidget( ann ), m_pixmapSelector( nullptr )
864 865 866 867
{
    m_caretAnn = static_cast< Okular::CaretAnnotation * >( ann );
}

868
void CaretAnnotationWidget::createStyleWidget( QFormLayout * formlayout )
869
{
870 871 872 873 874 875 876
    QWidget * widget = qobject_cast<QWidget *>( formlayout->parent() );

    addColorButton( widget, formlayout );
    addOpacitySpinBox( widget, formlayout );

    m_pixmapSelector = new PixmapPreviewSelector( widget );
    formlayout->addRow( i18n( "Caret symbol:" ), m_pixmapSelector );
877

Laurent Montel's avatar
Laurent Montel committed
878 879
    m_pixmapSelector->addItem( i18nc( "Symbol for caret annotations", "None" ), QStringLiteral("caret-none") );
    m_pixmapSelector->addItem( i18nc( "Symbol for caret annotations", "P" ), QStringLiteral("caret-p") );
880 881
    m_pixmapSelector->setIcon( caretSymbolToIcon( m_caretAnn->caretSymbol() ) );

Laurent Montel's avatar
Laurent Montel committed
882
    connect( m_pixmapSelector, &PixmapPreviewSelector::iconChanged, this, &AnnotationWidget::dataChanged );
883 884 885 886
}

void CaretAnnotationWidget::applyChanges()
{
887
    AnnotationWidget::applyChanges();
888 889 890 891 892
    m_caretAnn->setCaretSymbol( caretSymbolFromIcon( m_pixmapSelector->icon() ) );
}



893
#include "moc_annotationwidgets.cpp"