annotationwidgets.cpp 30 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.                                   *
 ***************************************************************************/

Albert Astals Cid's avatar
Albert Astals Cid committed
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>
Laurent Montel's avatar
Laurent Montel committed
22
#include <QIcon>
Pino Toscano's avatar
Pino Toscano committed
23
#include <kiconloader.h>
Lukáš Tinkl's avatar
Lukáš Tinkl committed
24 25
#include <KLocalizedString>
#include <QDebug>
26 27
#include <QGuiApplication>
#include <QList>
Laurent Montel's avatar
Laurent Montel committed
28
#include <QMimeDatabase>
29
#include <QPair>
30
#include <QSize>
Lukáš Tinkl's avatar
Lukáš Tinkl committed
31
#include <KFormat>
32
#include <QFormLayout>
Pino Toscano's avatar
Pino Toscano committed
33

34
#include "core/document.h"
35
#include "guiutils.h"
36
#include "pagepainter.h"
37

38 39
#define FILEATTACH_ICONSIZE 48

40 41 42 43 44
PixmapPreviewSelector::PixmapPreviewSelector( QWidget * parent )
  : QWidget( parent )
{
    QHBoxLayout * mainlay = new QHBoxLayout( this );
    mainlay->setMargin( 0 );
Albert Astals Cid's avatar
Albert Astals Cid committed
45
    m_comboItems = new KComboBox( this );
46
    mainlay->addWidget( m_comboItems );
47
    mainlay->setAlignment( m_comboItems, Qt::AlignTop );
48 49 50 51 52 53 54
    m_iconLabel = new QLabel( this );
    mainlay->addWidget( m_iconLabel );
    m_iconLabel->setSizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed );
    m_iconLabel->setAlignment( Qt::AlignCenter );
    m_iconLabel->setFrameStyle( QFrame::StyledPanel );
    setPreviewSize( 32 );

55 56 57
    setFocusPolicy( Qt::TabFocus );
    setFocusProxy( m_comboItems );

Laurent Montel's avatar
Laurent Montel committed
58
    connect( m_comboItems, SIGNAL(currentIndexChanged(QString)), this, SLOT(iconComboChanged(QString)) );
Laurent Montel's avatar
Laurent Montel committed
59
    connect( m_comboItems, &QComboBox::editTextChanged, this, &PixmapPreviewSelector::iconComboChanged );
60 61 62 63 64 65 66 67
}

PixmapPreviewSelector::~PixmapPreviewSelector()
{
}

void PixmapPreviewSelector::setIcon( const QString& icon )
{
Pino Toscano's avatar
Pino Toscano committed
68
    int id = m_comboItems->findData( QVariant( icon ), Qt::UserRole, Qt::MatchFixedString );
69
    if ( id == -1 )
Pino Toscano's avatar
Pino Toscano committed
70
        id = m_comboItems->findText( icon, Qt::MatchFixedString );
71 72 73 74
    if ( id > -1 )
    {
        m_comboItems->setCurrentIndex( id );
    }
75 76 77 78 79
    else if ( m_comboItems->isEditable() )
    {
        m_comboItems->addItem( icon, QVariant( icon ) );
        m_comboItems->setCurrentIndex( m_comboItems->findText( icon, Qt::MatchFixedString ) );
    }
80 81 82 83 84 85 86
}

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

Pino Toscano's avatar
Pino Toscano committed
87
void PixmapPreviewSelector::addItem( const QString& item, const QString& id )
88
{
Pino Toscano's avatar
Pino Toscano committed
89
    m_comboItems->addItem( item, QVariant( id ) );
90 91 92 93 94 95 96 97 98 99 100 101 102 103 104
    setIcon( m_icon );
}

void PixmapPreviewSelector::setPreviewSize( int size )
{
    m_previewSize = size;
    m_iconLabel->setFixedSize( m_previewSize + 8, m_previewSize + 8 );
    iconComboChanged( m_icon );
}

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

105 106 107 108 109
void PixmapPreviewSelector::setEditable( bool editable )
{
    m_comboItems->setEditable( editable );
}

110 111
void PixmapPreviewSelector::iconComboChanged( const QString& icon )
{
Pino Toscano's avatar
Pino Toscano committed
112
    int id = m_comboItems->findText( icon, Qt::MatchFixedString );
113 114 115 116 117 118 119 120
    if ( id >= 0 )
    {
        m_icon = m_comboItems->itemData( id ).toString();
    }
    else
    {
        m_icon = icon;
    }
Pino Toscano's avatar
Pino Toscano committed
121

122 123 124
    QPixmap pixmap = GuiUtils::loadStamp( m_icon, QSize(), m_previewSize );
    const QRect cr = m_iconLabel->contentsRect();
    if ( pixmap.width() > cr.width() || pixmap.height() > cr.height() )
Pino Toscano's avatar
Pino Toscano committed
125
        pixmap = pixmap.scaled( cr.size(), Qt::KeepAspectRatio, Qt::SmoothTransformation );
126
    m_iconLabel->setPixmap( pixmap );
127 128

    emit iconChanged( m_icon );
129 130 131
}


132
AnnotationWidget * AnnotationWidgetFactory::widgetFor( Okular::Annotation * ann )
Pino Toscano's avatar
Pino Toscano committed
133 134 135
{
    switch ( ann->subType() )
    {
136
        case Okular::Annotation::AStamp:
Pino Toscano's avatar
Pino Toscano committed
137 138
            return new StampAnnotationWidget( ann );
            break;
139
        case Okular::Annotation::AText:
Pino Toscano's avatar
Pino Toscano committed
140 141
            return new TextAnnotationWidget( ann );
            break;
142
        case Okular::Annotation::ALine:
Pino Toscano's avatar
Pino Toscano committed
143 144
            return new LineAnnotationWidget( ann );
            break;
145 146 147
        case Okular::Annotation::AHighlight:
            return new HighlightAnnotationWidget( ann );
            break;
148 149 150
        case Okular::Annotation::AInk:
            return new InkAnnotationWidget( ann );
            break;
151 152 153
        case Okular::Annotation::AGeom:
            return new GeomAnnotationWidget( ann );
            break;
154 155 156
        case Okular::Annotation::AFileAttachment:
            return new FileAttachmentAnnotationWidget( ann );
            break;
157 158 159
        case Okular::Annotation::ACaret:
            return new CaretAnnotationWidget( ann );
            break;
Pino Toscano's avatar
Pino Toscano committed
160 161 162 163
        // shut up gcc
        default:
            ;
    }
164 165
    // cases not covered yet: return a generic widget
    return new AnnotationWidget( ann );
Pino Toscano's avatar
Pino Toscano committed
166 167 168
}


169
AnnotationWidget::AnnotationWidget( Okular::Annotation * ann )
170
    : m_ann( ann )
Pino Toscano's avatar
Pino Toscano committed
171 172 173 174 175 176 177
{
}

AnnotationWidget::~AnnotationWidget()
{
}

178
Okular::Annotation::SubType AnnotationWidget::annotationType() const
Pino Toscano's avatar
Pino Toscano committed
179 180 181 182
{
    return m_ann->subType();
}

183
QWidget * AnnotationWidget::appearanceWidget()
184
{
185 186
    if ( m_appearanceWidget )
        return m_appearanceWidget;
187

188 189
    m_appearanceWidget = createAppearanceWidget();
    return m_appearanceWidget;
190 191
}

192 193 194 195 196 197 198 199 200
QWidget * AnnotationWidget::extraWidget()
{
    if ( m_extraWidget )
        return m_extraWidget;

    m_extraWidget = createExtraWidget();
    return m_extraWidget;
}

201 202
void AnnotationWidget::applyChanges()
{
203 204 205 206
    if (m_colorBn)
        m_ann->style().setColor( m_colorBn->color() );
    if (m_opacity)
        m_ann->style().setOpacity( (double)m_opacity->value() / 100.0 );
207 208 209 210 211
}

QWidget * AnnotationWidget::createAppearanceWidget()
{
    QWidget * widget = new QWidget();
212 213 214
    QFormLayout * formlayout = new QFormLayout( widget );
    formlayout->setLabelAlignment( Qt::AlignRight );
    formlayout->setFieldGrowthPolicy( QFormLayout::AllNonFixedFieldsGrow );
215

216
    createStyleWidget( formlayout );
217

218 219
    return widget;
}
220

221 222 223 224
void AnnotationWidget::createStyleWidget( QFormLayout * formlayout )
{
    Q_UNUSED( formlayout );
}
225

226 227 228 229 230 231
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 );
232 233
}

234
void AnnotationWidget::addOpacitySpinBox( QWidget * widget, QFormLayout * formlayout )
235
{
236 237 238 239 240 241 242 243 244 245 246
    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);
    connect( m_opacity, SIGNAL(valueChanged(int)), this, SIGNAL(dataChanged()) );
}

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

249 250
QWidget * AnnotationWidget::createExtraWidget()
{
251
    return nullptr;
252 253
}

Pino Toscano's avatar
Pino Toscano committed
254

255
TextAnnotationWidget::TextAnnotationWidget( Okular::Annotation * ann )
256
    : AnnotationWidget( ann )
Pino Toscano's avatar
Pino Toscano committed
257
{
258
    m_textAnn = static_cast< Okular::TextAnnotation * >( ann );
Pino Toscano's avatar
Pino Toscano committed
259 260
}

261
void TextAnnotationWidget::createStyleWidget( QFormLayout * formlayout )
Pino Toscano's avatar
Pino Toscano committed
262
{
263
    QWidget * widget = qobject_cast<QWidget *>( formlayout->parent() );
264 265 266

    if ( m_textAnn->textType() == Okular::TextAnnotation::Linked )
    {
267
        createPopupNoteStyleUi( widget, formlayout );
268 269 270
    }
    else if ( m_textAnn->textType() == Okular::TextAnnotation::InPlace )
    {
271
        if ( isTypewriter() )
272
            createTypewriterStyleUi( widget, formlayout );
273
        else
274
            createInlineNoteStyleUi( widget, formlayout );
275
    }
276 277
}

Pino Toscano's avatar
Pino Toscano committed
278 279
void TextAnnotationWidget::applyChanges()
{
280
    AnnotationWidget::applyChanges();
Tobias Koenig's avatar
Tobias Koenig committed
281
    if ( m_textAnn->textType() == Okular::TextAnnotation::Linked )
Pino Toscano's avatar
Pino Toscano committed
282
    {
283
        Q_ASSERT( m_pixmapSelector );
Tobias Koenig's avatar
Tobias Koenig committed
284
        m_textAnn->setTextIcon( m_pixmapSelector->icon() );
Pino Toscano's avatar
Pino Toscano committed
285
    }
286 287
    else if ( m_textAnn->textType() == Okular::TextAnnotation::InPlace )
    {
288
        Q_ASSERT( m_fontReq );
289
        m_textAnn->setTextFont( m_fontReq->font() );
290 291
        if ( !isTypewriter() )
        {
292
            Q_ASSERT( m_textAlign && m_spinWidth );
293 294 295
            m_textAnn->setInplaceAlignment( m_textAlign->currentIndex() );
            m_textAnn->style().setWidth( m_spinWidth->value() );
        }
296 297 298 299 300
        else
        {
            Q_ASSERT( m_textColorBn );
            m_textAnn->setTextColor( m_textColorBn->color() );
        }
301
    }
Pino Toscano's avatar
Pino Toscano committed
302 303
}

304 305 306 307 308
void TextAnnotationWidget::createPopupNoteStyleUi( QWidget * widget, QFormLayout * formlayout  ) {
    addColorButton( widget, formlayout );
    addOpacitySpinBox( widget, formlayout );
    addVerticalSpacer( formlayout );
    addPixmapSelector( widget, formlayout );
309 310
}

311 312 313 314 315 316 317 318
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 );
319 320
}

321 322 323
void TextAnnotationWidget::createTypewriterStyleUi( QWidget * widget, QFormLayout * formlayout  ) {
    addFontRequester( widget, formlayout );
    addTextColorButton( widget, formlayout );
324 325
}

326
void TextAnnotationWidget::addPixmapSelector( QWidget * widget, QFormLayout * formlayout )
327
{
328 329 330 331 332 333 334 335 336 337 338
    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 );
339 340
}

341
void TextAnnotationWidget::addFontRequester( QWidget * widget, QFormLayout * formlayout )
342 343
{
    m_fontReq = new KFontRequester( widget );
344
    formlayout->addRow( i18n( "Font:" ), m_fontReq );
345 346 347 348
    m_fontReq->setFont( m_textAnn->textFont() );
    connect( m_fontReq, &KFontRequester::fontSelected, this, &AnnotationWidget::dataChanged );
}

349
void TextAnnotationWidget::addTextColorButton( QWidget * widget, QFormLayout * formlayout )
350 351 352
{
    m_textColorBn = new KColorButton( widget );
    m_textColorBn->setColor( m_textAnn->textColor() );
353
    formlayout->addRow( i18n( "Text &color:" ), m_textColorBn );
354 355 356
    connect( m_textColorBn, &KColorButton::changed, this, &AnnotationWidget::dataChanged );
}

357
void TextAnnotationWidget::addTextAlignComboBox( QWidget * widget, QFormLayout * formlayout )
358
{
359

360
    m_textAlign = new KComboBox( widget );
361
    formlayout->addRow( i18n( "&Align:" ), m_textAlign );
362 363 364 365 366 367 368
    m_textAlign->addItem( i18n("Left") );
    m_textAlign->addItem( i18n("Center") );
    m_textAlign->addItem( i18n("Right") );
    m_textAlign->setCurrentIndex( m_textAnn->inplaceAlignment() );
    connect( m_textAlign, SIGNAL(currentIndexChanged(int)), this, SIGNAL(dataChanged()) );
}

369
void TextAnnotationWidget::addWidthSpinBox( QWidget * widget, QFormLayout * formlayout )
370 371
{
    m_spinWidth = new QDoubleSpinBox( widget );
372
    formlayout->addRow( i18n( "Border &width:" ), m_spinWidth );
373 374 375 376 377
    m_spinWidth->setRange( 0, 100 );
    m_spinWidth->setValue( m_textAnn->style().width() );
    m_spinWidth->setSingleStep( 0.1 );
    connect( m_spinWidth, SIGNAL(valueChanged(double)), this, SIGNAL(dataChanged()) );
}
Pino Toscano's avatar
Pino Toscano committed
378

379
StampAnnotationWidget::StampAnnotationWidget( Okular::Annotation * ann )
380
    : AnnotationWidget( ann ), m_pixmapSelector( nullptr )
Pino Toscano's avatar
Pino Toscano committed
381
{
382
    m_stampAnn = static_cast< Okular::StampAnnotation * >( ann );
Pino Toscano's avatar
Pino Toscano committed
383 384
}

385
void StampAnnotationWidget::createStyleWidget( QFormLayout * formlayout )
Pino Toscano's avatar
Pino Toscano committed
386
{
387 388 389 390 391 392 393
    QWidget * widget = qobject_cast<QWidget *>( formlayout->parent() );

    addOpacitySpinBox( widget, formlayout );
    addVerticalSpacer( formlayout );

    m_pixmapSelector = new PixmapPreviewSelector( widget );
    formlayout->addRow( i18n( "Stamp symbol:" ), m_pixmapSelector );
394
    m_pixmapSelector->setEditable( true );
Pino Toscano's avatar
Pino Toscano committed
395

Laurent Montel's avatar
Laurent Montel committed
396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413
    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") );
Tobias Koenig's avatar
Tobias Koenig committed
414
    m_pixmapSelector->setIcon( m_stampAnn->stampIconName() );
415
    m_pixmapSelector->setPreviewSize( 64 );
Pino Toscano's avatar
Pino Toscano committed
416

Laurent Montel's avatar
Laurent Montel committed
417
    connect( m_pixmapSelector, &PixmapPreviewSelector::iconChanged, this, &AnnotationWidget::dataChanged );
Pino Toscano's avatar
Pino Toscano committed
418 419 420 421
}

void StampAnnotationWidget::applyChanges()
{
422
    AnnotationWidget::applyChanges();
Tobias Koenig's avatar
Tobias Koenig committed
423
    m_stampAnn->setStampIconName( m_pixmapSelector->icon() );
Pino Toscano's avatar
Pino Toscano committed
424 425 426 427
}



428
LineAnnotationWidget::LineAnnotationWidget( Okular::Annotation * ann )
429
    : AnnotationWidget( ann )
Pino Toscano's avatar
Pino Toscano committed
430
{
431
    m_lineAnn = static_cast< Okular::LineAnnotation * >( ann );
Tobias Koenig's avatar
Tobias Koenig committed
432
    if ( m_lineAnn->linePoints().count() == 2 )
Pino Toscano's avatar
Pino Toscano committed
433
        m_lineType = 0; // line
Tobias Koenig's avatar
Tobias Koenig committed
434
    else if ( m_lineAnn->lineClosed() )
Pino Toscano's avatar
Pino Toscano committed
435 436 437 438 439
        m_lineType = 1; // polygon
    else
        m_lineType = 2; // polyline
}

440
void LineAnnotationWidget::createStyleWidget( QFormLayout * formlayout )
Pino Toscano's avatar
Pino Toscano committed
441
{
442
    QWidget * widget = qobject_cast<QWidget *>( formlayout->parent() );
443

444 445 446 447 448 449 450 451
    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 );
452

453 454
    // Straight line
    if ( m_lineType == 0 )
455
    {
456 457
        addVerticalSpacer( formlayout );
        formlayout->addRow( i18n( "&Width:" ), m_spinSize );
458 459

        //Line Term Styles
460
        addVerticalSpacer( formlayout );
461
        m_startStyleCombo = new QComboBox( widget );
462
        formlayout->addRow( i18n( "Line start:" ), m_startStyleCombo);
463
        m_endStyleCombo = new QComboBox( widget );
464 465
        formlayout->addRow( i18n( "Line end:" ), m_endStyleCombo);
        //FIXME: Where does the tooltip goes??
466

467
        const QList<QPair<Okular::LineAnnotation::TermStyle, QString>> termStyles
468
        {
469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484
            { 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 );
485 486 487 488 489
        }

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

490 491 492 493 494 495
        //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 );
496

497 498 499 500
        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
501

502 503
        connect( m_startStyleCombo, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &LineAnnotationWidget::dataChanged );
        connect( m_endStyleCombo, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &LineAnnotationWidget::dataChanged );
504 505 506
        connect( m_spinLL, SIGNAL(valueChanged(double)), this, SIGNAL(dataChanged()) );
        connect( m_spinLLE, SIGNAL(valueChanged(double)), this, SIGNAL(dataChanged()) );
    }
507
    else if ( m_lineType == 1 ) // Polygon
508
    {
509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528
        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
529 530
        connect( m_innerColor, &KColorButton::changed, this, &AnnotationWidget::dataChanged );
        connect( m_useColor, &QAbstractButton::toggled, this, &AnnotationWidget::dataChanged );
531
        connect( m_useColor, &QCheckBox::toggled, m_innerColor, &KColorButton::setEnabled );
532
    }
Pino Toscano's avatar
Pino Toscano committed
533 534 535 536
}

void LineAnnotationWidget::applyChanges()
{
537
    AnnotationWidget::applyChanges();
Pino Toscano's avatar
Pino Toscano committed
538 539
    if ( m_lineType == 0 )
    {
540
        Q_ASSERT(m_spinLL && m_spinLLE && m_startStyleCombo && m_endStyleCombo);
Tobias Koenig's avatar
Tobias Koenig committed
541 542
        m_lineAnn->setLineLeadingForwardPoint( m_spinLL->value() );
        m_lineAnn->setLineLeadingBackwardPoint( m_spinLLE->value() );
543 544
        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
545
    }
546 547
    else if ( m_lineType == 1 )
    {
548
        Q_ASSERT( m_useColor && m_innerColor );
549 550 551 552 553 554 555 556 557
        if ( !m_useColor->isChecked() )
        {
            m_lineAnn->setLineInnerColor( QColor() );
        }
        else
        {
            m_lineAnn->setLineInnerColor( m_innerColor->color() );
        }
    }
558
    Q_ASSERT( m_spinSize );
559
    m_lineAnn->style().setWidth( m_spinSize->value() );
Pino Toscano's avatar
Pino Toscano committed
560 561
}

562 563 564 565 566 567 568 569 570 571 572 573
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 } );
574
    LineAnnotPainter linepainter { &prototype, QSize { iconSize, iconSize }, 1, QTransform() };
575 576 577 578
    linepainter.draw( image );
    return QIcon( QPixmap::fromImage( image ) );
}

Pino Toscano's avatar
Pino Toscano committed
579 580


581 582 583 584 585 586
InkAnnotationWidget::InkAnnotationWidget( Okular::Annotation * ann )
    : AnnotationWidget( ann )
{
    m_inkAnn = static_cast< Okular::InkAnnotation * >( ann );
}

587
void InkAnnotationWidget::createStyleWidget( QFormLayout * formlayout )
588
{
589 590 591 592 593 594 595 596 597
    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 );
598 599 600 601 602 603 604 605 606 607 608 609 610 611 612

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

    connect( m_spinSize, SIGNAL(valueChanged(double)), this, SIGNAL(dataChanged()) );
}

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



613
HighlightAnnotationWidget::HighlightAnnotationWidget( Okular::Annotation * ann )
614
    : AnnotationWidget( ann )
615 616 617 618
{
    m_hlAnn = static_cast< Okular::HighlightAnnotation * >( ann );
}

619
void HighlightAnnotationWidget::createStyleWidget( QFormLayout * formlayout )
620
{
621
    QWidget * widget = qobject_cast<QWidget *>( formlayout->parent() );
622

623 624
    m_typeCombo = new KComboBox( widget );
    formlayout->addRow( i18n( "Type:" ), m_typeCombo );
625
    m_typeCombo->addItem( i18n( "Highlight" ) );
626
    m_typeCombo->addItem( i18n( "Squiggle" ) );
627
    m_typeCombo->addItem( i18n( "Underline" ) );
Pino Toscano's avatar
Pino Toscano committed
628
    m_typeCombo->addItem( i18n( "Strike out" ) );
Tobias Koenig's avatar
Tobias Koenig committed
629
    m_typeCombo->setCurrentIndex( m_hlAnn->highlightType() );
630

631 632 633
    addVerticalSpacer( formlayout );
    addColorButton( widget, formlayout );
    addOpacitySpinBox( widget, formlayout );
634

635
    connect( m_typeCombo, SIGNAL(currentIndexChanged(int)), this, SIGNAL(dataChanged()) );
636 637 638 639
}

void HighlightAnnotationWidget::applyChanges()
{
640
    AnnotationWidget::applyChanges();
Tobias Koenig's avatar
Tobias Koenig committed
641
    m_hlAnn->setHighlightType( (Okular::HighlightAnnotation::HighlightType)m_typeCombo->currentIndex() );
642 643 644 645
}



646
GeomAnnotationWidget::GeomAnnotationWidget( Okular::Annotation * ann )
647
    : AnnotationWidget( ann )
648 649 650 651
{
    m_geomAnn = static_cast< Okular::GeomAnnotation * >( ann );
}

652
void GeomAnnotationWidget::createStyleWidget( QFormLayout * formlayout )
653
{
654 655
    QWidget * widget = qobject_cast<QWidget *>( formlayout->parent() );

656
    m_typeCombo = new KComboBox( widget );
657 658 659 660 661 662 663
    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);
664
    m_innerColor = new KColorButton( widget );
665 666 667
    colorlay->addWidget( m_innerColor);
    formlayout->addRow( i18n( "Shape fill:" ), colorlay );
    addVerticalSpacer( formlayout );
668
    m_spinSize = new QDoubleSpinBox( widget );
669
    formlayout->addRow( i18n( "&Width:" ), m_spinSize );
670 671 672

    m_typeCombo->addItem( i18n( "Rectangle" ) );
    m_typeCombo->addItem( i18n( "Ellipse" ) );
Tobias Koenig's avatar
Tobias Koenig committed
673 674 675
    m_typeCombo->setCurrentIndex( m_geomAnn->geometricalType() );
    m_innerColor->setColor( m_geomAnn->geometricalInnerColor() );
    if ( m_geomAnn->geometricalInnerColor().isValid() )
676 677 678 679 680 681 682
    {
        m_useColor->setChecked( true );
    }
    else
    {
        m_innerColor->setEnabled( false );
    }
683
    m_spinSize->setRange( 0, 100 );
684
    m_spinSize->setValue( m_geomAnn->style().width() );
685

Laurent Montel's avatar
Laurent Montel committed
686
    connect( m_typeCombo, SIGNAL(currentIndexChanged(int)), this, SIGNAL(dataChanged()) );
Laurent Montel's avatar
Laurent Montel committed
687 688
    connect( m_innerColor, &KColorButton::changed, this, &AnnotationWidget::dataChanged );
    connect( m_useColor, &QAbstractButton::toggled, this, &AnnotationWidget::dataChanged );
Laurent Montel's avatar
Laurent Montel committed
689
    connect(m_useColor, &QCheckBox::toggled, m_innerColor, &KColorButton::setEnabled);
Laurent Montel's avatar
Laurent Montel committed
690
    connect( m_spinSize, SIGNAL(valueChanged(double)), this, SIGNAL(dataChanged()) );
691 692 693 694
}

void GeomAnnotationWidget::applyChanges()
{
695
    AnnotationWidget::applyChanges();
Tobias Koenig's avatar
Tobias Koenig committed
696
    m_geomAnn->setGeometricalType( (Okular::GeomAnnotation::GeomType)m_typeCombo->currentIndex() );
697 698
    if ( !m_useColor->isChecked() )
    {
Tobias Koenig's avatar
Tobias Koenig committed
699
        m_geomAnn->setGeometricalInnerColor( QColor() );
700 701 702
    }
    else
    {
Tobias Koenig's avatar
Tobias Koenig committed
703
        m_geomAnn->setGeometricalInnerColor( m_innerColor->color() );
704
    }
705
    m_geomAnn->style().setWidth( m_spinSize->value() );
706 707
}

708 709 710


FileAttachmentAnnotationWidget::FileAttachmentAnnotationWidget( Okular::Annotation * ann )
711
    : AnnotationWidget( ann ), m_pixmapSelector( nullptr )
712 713 714 715
{
    m_attachAnn = static_cast< Okular::FileAttachmentAnnotation * >( ann );
}

716
void FileAttachmentAnnotationWidget::createStyleWidget( QFormLayout * formlayout )
717
{
718 719 720 721 722 723
    QWidget * widget = qobject_cast<QWidget *>( formlayout->parent() );

    addOpacitySpinBox( widget, formlayout );

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

Laurent Montel's avatar
Laurent Montel committed
726 727 728 729
    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") );
730 731
    m_pixmapSelector->setIcon( m_attachAnn->fileIconName() );

Laurent Montel's avatar
Laurent Montel committed
732
    connect( m_pixmapSelector, &PixmapPreviewSelector::iconChanged, this, &AnnotationWidget::dataChanged );
733 734 735 736 737 738 739 740 741
}

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();
742
    const QString sizeString = size <= 0 ? i18nc( "Not available size", "N/A" ) : KFormat().formatByteSize( size );
743
    const QString descString = ef->description().isEmpty() ? i18n( "No description available." ) : ef->description();
744

745 746 747 748 749
    QHBoxLayout * mainLay = new QHBoxLayout( widget );
    QFormLayout * lay = new QFormLayout();
    mainLay->addLayout( lay );

    QLabel * tmplabel = new QLabel( ef->name() , widget );
750
    tmplabel->setTextInteractionFlags( Qt::TextSelectableByMouse );
751
    lay->addRow( i18n( "Name:" ), tmplabel );
752

753
    tmplabel = new QLabel( sizeString, widget );
754
    tmplabel->setTextInteractionFlags( Qt::TextSelectableByMouse );
755
    lay->addRow( i18n( "&Width:" ), tmplabel );
756

757 758 759 760
    tmplabel = new QLabel( widget );
    tmplabel->setTextFormat( Qt::PlainText );
    tmplabel->setWordWrap( true );
    tmplabel->setText( descString );
761
    tmplabel->setTextInteractionFlags( Qt::TextSelectableByMouse );
762
    lay->addRow( i18n( "Description:" ), tmplabel );
763

Frederik Gladhorn's avatar
Frederik Gladhorn committed
764 765 766
    QMimeDatabase db;
    QMimeType mime = db.mimeTypeForFile( ef->name(), QMimeDatabase::MatchExtension);
    if ( mime.isValid() )
767 768
    {
        tmplabel = new QLabel( widget );
Frederik Gladhorn's avatar
Frederik Gladhorn committed
769
        tmplabel->setPixmap( QIcon::fromTheme( mime.iconName() ).pixmap( FILEATTACH_ICONSIZE, FILEATTACH_ICONSIZE ) );
770
        tmplabel->setFixedSize( FILEATTACH_ICONSIZE, FILEATTACH_ICONSIZE );
771 772 773 774
        QVBoxLayout * tmpLayout = new QVBoxLayout( widget );
        tmpLayout->setAlignment( Qt::AlignTop );
        mainLay->addLayout( tmpLayout );
        tmpLayout->addWidget( tmplabel );
775 776 777 778 779 780 781
    }

    return widget;
}

void FileAttachmentAnnotationWidget::applyChanges()
{
782
    AnnotationWidget::applyChanges();
783
    m_attachAnn->setFileIconName( m_pixmapSelector->icon() );
784 785 786
}


787 788 789 790 791 792

static QString caretSymbolToIcon( Okular::CaretAnnotation::CaretSymbol symbol )
{
    switch ( symbol )
    {
        case Okular::CaretAnnotation::None:
Laurent Montel's avatar
Laurent Montel committed
793
            return QStringLiteral( "caret-none" );
794
        case Okular::CaretAnnotation::P:
Laurent Montel's avatar
Laurent Montel committed
795
            return QStringLiteral( "caret-p" );
796 797 798 799 800 801 802 803 804 805 806 807 808 809
    }
    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 )
810
    : AnnotationWidget( ann ), m_pixmapSelector( nullptr )
811 812 813 814
{
    m_caretAnn = static_cast< Okular::CaretAnnotation * >( ann );
}

815
void CaretAnnotationWidget::createStyleWidget( QFormLayout * formlayout )
816
{
817 818 819 820 821 822 823
    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 );
824

Laurent Montel's avatar
Laurent Montel committed
825 826
    m_pixmapSelector->addItem( i18nc( "Symbol for caret annotations", "None" ), QStringLiteral("caret-none") );
    m_pixmapSelector->addItem( i18nc( "Symbol for caret annotations", "P" ), QStringLiteral("caret-p") );
827 828
    m_pixmapSelector->setIcon( caretSymbolToIcon( m_caretAnn->caretSymbol() ) );

Laurent Montel's avatar
Laurent Montel committed
829
    connect( m_pixmapSelector, &PixmapPreviewSelector::iconChanged, this, &AnnotationWidget::dataChanged );
830 831 832 833
}

void CaretAnnotationWidget::applyChanges()
{
834
    AnnotationWidget::applyChanges();
835 836 837 838 839
    m_caretAnn->setCaretSymbol( caretSymbolFromIcon( m_pixmapSelector->icon() ) );
}



840
#include "moc_annotationwidgets.cpp"