1 /*
2 SPDX-FileCopyrightText: 2007 Pino Toscano <pino@kde.org>
3 SPDX-FileCopyrightText: 2018 Intevation GmbH <intevation@intevation.de>
4
5 Work sponsored by the LiMux project of the city of Munich:
6 SPDX-FileCopyrightText: 2017 Klarälvdalens Datakonsult AB a KDAB Group company <info@kdab.com>
7
8 SPDX-License-Identifier: GPL-2.0-or-later
9 */
10
11 #include "formwidgets.h"
12 #include "pageviewutils.h"
13 #include "revisionviewer.h"
14 #include "signaturepropertiesdialog.h"
15
16 #include <KLineEdit>
17 #include <KLocalizedString>
18 #include <KStandardAction>
19 #include <QAction>
20 #include <QButtonGroup>
21 #include <QEvent>
22 #include <QKeyEvent>
23 #include <QMenu>
24 #include <QPainter>
25 #include <QUrl>
26
27 // local includes
28 #include "core/action.h"
29 #include "core/document.h"
30 #include "debug_ui.h"
31
FormWidgetsController(Okular::Document * doc)32 FormWidgetsController::FormWidgetsController(Okular::Document *doc)
33 : QObject(doc)
34 , m_doc(doc)
35 {
36 // emit changed signal when a form has changed
37 connect(this, &FormWidgetsController::formTextChangedByUndoRedo, this, &FormWidgetsController::changed);
38 connect(this, &FormWidgetsController::formListChangedByUndoRedo, this, &FormWidgetsController::changed);
39 connect(this, &FormWidgetsController::formComboChangedByUndoRedo, this, &FormWidgetsController::changed);
40
41 // connect form modification signals to and from document
42 connect(this, &FormWidgetsController::formTextChangedByWidget, doc, &Okular::Document::editFormText);
43 connect(doc, &Okular::Document::formTextChangedByUndoRedo, this, &FormWidgetsController::formTextChangedByUndoRedo);
44
45 connect(this, &FormWidgetsController::formListChangedByWidget, doc, &Okular::Document::editFormList);
46 connect(doc, &Okular::Document::formListChangedByUndoRedo, this, &FormWidgetsController::formListChangedByUndoRedo);
47
48 connect(this, &FormWidgetsController::formComboChangedByWidget, doc, &Okular::Document::editFormCombo);
49 connect(doc, &Okular::Document::formComboChangedByUndoRedo, this, &FormWidgetsController::formComboChangedByUndoRedo);
50
51 connect(this, &FormWidgetsController::formButtonsChangedByWidget, doc, &Okular::Document::editFormButtons);
52 connect(doc, &Okular::Document::formButtonsChangedByUndoRedo, this, &FormWidgetsController::slotFormButtonsChangedByUndoRedo);
53
54 // Connect undo/redo signals
55 connect(this, &FormWidgetsController::requestUndo, doc, &Okular::Document::undo);
56 connect(this, &FormWidgetsController::requestRedo, doc, &Okular::Document::redo);
57
58 connect(doc, &Okular::Document::canUndoChanged, this, &FormWidgetsController::canUndoChanged);
59 connect(doc, &Okular::Document::canRedoChanged, this, &FormWidgetsController::canRedoChanged);
60
61 // Connect the generic formWidget refresh signal
62 connect(doc, &Okular::Document::refreshFormWidget, this, &FormWidgetsController::refreshFormWidget);
63 }
64
~FormWidgetsController()65 FormWidgetsController::~FormWidgetsController()
66 {
67 }
68
signalAction(Okular::Action * a)69 void FormWidgetsController::signalAction(Okular::Action *a)
70 {
71 emit action(a);
72 }
73
processScriptAction(Okular::Action * a,Okular::FormField * field,Okular::Annotation::AdditionalActionType type)74 void FormWidgetsController::processScriptAction(Okular::Action *a, Okular::FormField *field, Okular::Annotation::AdditionalActionType type)
75 {
76 // If it's not a Action Script or if the field is not a FormText, handle it normally
77 if (a->actionType() != Okular::Action::Script || field->type() != Okular::FormField::FormText) {
78 emit action(a);
79 return;
80 }
81 switch (type) {
82 // These cases are to be handled by the FormField text, so we let it happen.
83 case Okular::Annotation::FocusIn:
84 case Okular::Annotation::FocusOut:
85 return;
86 case Okular::Annotation::PageOpening:
87 case Okular::Annotation::PageClosing:
88 case Okular::Annotation::CursorEntering:
89 case Okular::Annotation::CursorLeaving:
90 case Okular::Annotation::MousePressed:
91 case Okular::Annotation::MouseReleased:
92 emit action(a);
93 }
94 }
95
registerRadioButton(FormWidgetIface * fwButton,Okular::FormFieldButton * formButton)96 void FormWidgetsController::registerRadioButton(FormWidgetIface *fwButton, Okular::FormFieldButton *formButton)
97 {
98 if (!fwButton)
99 return;
100
101 QAbstractButton *button = dynamic_cast<QAbstractButton *>(fwButton);
102 if (!button) {
103 qWarning() << "fwButton is not a QAbstractButton" << fwButton;
104 return;
105 }
106
107 QList<RadioData>::iterator it = m_radios.begin(), itEnd = m_radios.end();
108 const int id = formButton->id();
109 m_buttons.insert(id, button);
110 for (; it != itEnd; ++it) {
111 const RadioData &rd = *it;
112 const QList<int>::const_iterator idsIt = std::find(rd.ids.begin(), rd.ids.end(), id);
113 if (idsIt != rd.ids.constEnd()) {
114 qCDebug(OkularUiDebug) << "Adding id" << id << "To group including" << rd.ids;
115 rd.group->addButton(button);
116 rd.group->setId(button, id);
117 return;
118 }
119 }
120
121 const QList<int> siblings = formButton->siblings();
122
123 RadioData newdata;
124 newdata.ids = siblings;
125 newdata.ids.append(id);
126 newdata.group = new QButtonGroup();
127 newdata.group->addButton(button);
128 newdata.group->setId(button, id);
129
130 // Groups of 1 (like checkboxes) can't be exclusive
131 if (siblings.isEmpty())
132 newdata.group->setExclusive(false);
133
134 connect(newdata.group, QOverload<QAbstractButton *>::of(&QButtonGroup::buttonClicked), this, &FormWidgetsController::slotButtonClicked);
135 m_radios.append(newdata);
136 }
137
dropRadioButtons()138 void FormWidgetsController::dropRadioButtons()
139 {
140 QList<RadioData>::iterator it = m_radios.begin(), itEnd = m_radios.end();
141 for (; it != itEnd; ++it) {
142 delete (*it).group;
143 }
144 m_radios.clear();
145 m_buttons.clear();
146 }
147
canUndo()148 bool FormWidgetsController::canUndo()
149 {
150 return m_doc->canUndo();
151 }
152
canRedo()153 bool FormWidgetsController::canRedo()
154 {
155 return m_doc->canRedo();
156 }
157
shouldFormWidgetBeShown(Okular::FormField * form)158 bool FormWidgetsController::shouldFormWidgetBeShown(Okular::FormField *form)
159 {
160 return !form->isReadOnly() || form->type() == Okular::FormField::FormSignature;
161 }
162
slotButtonClicked(QAbstractButton * button)163 void FormWidgetsController::slotButtonClicked(QAbstractButton *button)
164 {
165 int pageNumber = -1;
166 CheckBoxEdit *check = qobject_cast<CheckBoxEdit *>(button);
167 if (check) {
168 // Checkboxes need to be uncheckable so if clicking a checked one
169 // disable the exclusive status temporarily and uncheck it
170 Okular::FormFieldButton *formButton = static_cast<Okular::FormFieldButton *>(check->formField());
171 if (formButton->state()) {
172 const bool wasExclusive = button->group()->exclusive();
173 button->group()->setExclusive(false);
174 check->setChecked(false);
175 button->group()->setExclusive(wasExclusive);
176 }
177 pageNumber = check->pageItem()->pageNumber();
178 } else if (RadioButtonEdit *radio = qobject_cast<RadioButtonEdit *>(button)) {
179 pageNumber = radio->pageItem()->pageNumber();
180 }
181
182 const QList<QAbstractButton *> buttons = button->group()->buttons();
183 QList<bool> checked;
184 QList<bool> prevChecked;
185 QList<Okular::FormFieldButton *> formButtons;
186
187 for (QAbstractButton *button : buttons) {
188 checked.append(button->isChecked());
189 Okular::FormFieldButton *formButton = static_cast<Okular::FormFieldButton *>(dynamic_cast<FormWidgetIface *>(button)->formField());
190 formButtons.append(formButton);
191 prevChecked.append(formButton->state());
192 }
193 if (checked != prevChecked)
194 emit formButtonsChangedByWidget(pageNumber, formButtons, checked);
195 if (check) {
196 // The formButtonsChangedByWidget signal changes the value of the underlying
197 // Okular::FormField of the checkbox. We need to execute the activation
198 // action after this.
199 check->doActivateAction();
200 }
201 }
202
slotFormButtonsChangedByUndoRedo(int pageNumber,const QList<Okular::FormFieldButton * > & formButtons)203 void FormWidgetsController::slotFormButtonsChangedByUndoRedo(int pageNumber, const QList<Okular::FormFieldButton *> &formButtons)
204 {
205 for (const Okular::FormFieldButton *formButton : formButtons) {
206 int id = formButton->id();
207 QAbstractButton *button = m_buttons[id];
208 CheckBoxEdit *check = qobject_cast<CheckBoxEdit *>(button);
209 if (check) {
210 emit refreshFormWidget(check->formField());
211 }
212 // temporarily disable exclusiveness of the button group
213 // since it breaks doing/redoing steps into which all the checkboxes
214 // are unchecked
215 const bool wasExclusive = button->group()->exclusive();
216 button->group()->setExclusive(false);
217 bool checked = formButton->state();
218 button->setChecked(checked);
219 button->group()->setExclusive(wasExclusive);
220 button->setFocus();
221 }
222 emit changed(pageNumber);
223 }
224
createWidget(Okular::FormField * ff,QWidget * parent)225 FormWidgetIface *FormWidgetFactory::createWidget(Okular::FormField *ff, QWidget *parent)
226 {
227 FormWidgetIface *widget = nullptr;
228
229 switch (ff->type()) {
230 case Okular::FormField::FormButton: {
231 Okular::FormFieldButton *ffb = static_cast<Okular::FormFieldButton *>(ff);
232 switch (ffb->buttonType()) {
233 case Okular::FormFieldButton::Push:
234 widget = new PushButtonEdit(ffb, parent);
235 break;
236 case Okular::FormFieldButton::CheckBox:
237 widget = new CheckBoxEdit(ffb, parent);
238 break;
239 case Okular::FormFieldButton::Radio:
240 widget = new RadioButtonEdit(ffb, parent);
241 break;
242 default:;
243 }
244 break;
245 }
246 case Okular::FormField::FormText: {
247 Okular::FormFieldText *fft = static_cast<Okular::FormFieldText *>(ff);
248 switch (fft->textType()) {
249 case Okular::FormFieldText::Multiline:
250 widget = new TextAreaEdit(fft, parent);
251 break;
252 case Okular::FormFieldText::Normal:
253 widget = new FormLineEdit(fft, parent);
254 break;
255 case Okular::FormFieldText::FileSelect:
256 widget = new FileEdit(fft, parent);
257 break;
258 }
259 break;
260 }
261 case Okular::FormField::FormChoice: {
262 Okular::FormFieldChoice *ffc = static_cast<Okular::FormFieldChoice *>(ff);
263 switch (ffc->choiceType()) {
264 case Okular::FormFieldChoice::ListBox:
265 widget = new ListEdit(ffc, parent);
266 break;
267 case Okular::FormFieldChoice::ComboBox:
268 widget = new ComboEdit(ffc, parent);
269 break;
270 }
271 break;
272 }
273 case Okular::FormField::FormSignature: {
274 Okular::FormFieldSignature *ffs = static_cast<Okular::FormFieldSignature *>(ff);
275 if (ffs->isVisible() && ffs->signatureType() != Okular::FormFieldSignature::UnknownType)
276 widget = new SignatureEdit(ffs, parent);
277 break;
278 }
279 default:;
280 }
281
282 if (!FormWidgetsController::shouldFormWidgetBeShown(ff))
283 widget->setVisibility(false);
284
285 return widget;
286 }
287
FormWidgetIface(QWidget * w,Okular::FormField * ff)288 FormWidgetIface::FormWidgetIface(QWidget *w, Okular::FormField *ff)
289 : m_controller(nullptr)
290 , m_ff(ff)
291 , m_widget(w)
292 , m_pageItem(nullptr)
293 {
294 }
295
~FormWidgetIface()296 FormWidgetIface::~FormWidgetIface()
297 {
298 }
299
rect() const300 Okular::NormalizedRect FormWidgetIface::rect() const
301 {
302 return m_ff->rect();
303 }
304
setWidthHeight(int w,int h)305 void FormWidgetIface::setWidthHeight(int w, int h)
306 {
307 m_widget->resize(w, h);
308 }
309
moveTo(int x,int y)310 void FormWidgetIface::moveTo(int x, int y)
311 {
312 m_widget->move(x, y);
313 }
314
setVisibility(bool visible)315 bool FormWidgetIface::setVisibility(bool visible)
316 {
317 bool hadfocus = m_widget->hasFocus();
318 if (hadfocus)
319 m_widget->clearFocus();
320 m_widget->setVisible(visible);
321 return hadfocus;
322 }
323
setCanBeFilled(bool fill)324 void FormWidgetIface::setCanBeFilled(bool fill)
325 {
326 m_widget->setEnabled(fill);
327 }
328
setPageItem(PageViewItem * pageItem)329 void FormWidgetIface::setPageItem(PageViewItem *pageItem)
330 {
331 m_pageItem = pageItem;
332 }
333
setFormField(Okular::FormField * field)334 void FormWidgetIface::setFormField(Okular::FormField *field)
335 {
336 m_ff = field;
337 }
338
formField() const339 Okular::FormField *FormWidgetIface::formField() const
340 {
341 return m_ff;
342 }
343
pageItem() const344 PageViewItem *FormWidgetIface::pageItem() const
345 {
346 return m_pageItem;
347 }
348
setFormWidgetsController(FormWidgetsController * controller)349 void FormWidgetIface::setFormWidgetsController(FormWidgetsController *controller)
350 {
351 m_controller = controller;
352 QObject *obj = dynamic_cast<QObject *>(this);
353 QObject::connect(m_controller, &FormWidgetsController::refreshFormWidget, obj, [this](Okular::FormField *form) { slotRefresh(form); });
354 }
355
slotRefresh(Okular::FormField * form)356 void FormWidgetIface::slotRefresh(Okular::FormField *form)
357 {
358 if (m_ff != form) {
359 return;
360 }
361 setVisibility(form->isVisible() && m_controller->shouldFormWidgetBeShown(form));
362
363 m_widget->setEnabled(!form->isReadOnly());
364 }
365
PushButtonEdit(Okular::FormFieldButton * button,QWidget * parent)366 PushButtonEdit::PushButtonEdit(Okular::FormFieldButton *button, QWidget *parent)
367 : QPushButton(parent)
368 , FormWidgetIface(this, button)
369 {
370 setText(button->caption());
371
372 if (button->caption().isEmpty()) {
373 setFlat(true);
374 }
375
376 setVisible(button->isVisible());
377 setCursor(Qt::ArrowCursor);
378 }
379
CheckBoxEdit(Okular::FormFieldButton * button,QWidget * parent)380 CheckBoxEdit::CheckBoxEdit(Okular::FormFieldButton *button, QWidget *parent)
381 : QCheckBox(parent)
382 , FormWidgetIface(this, button)
383 {
384 setText(button->caption());
385
386 setVisible(button->isVisible());
387 setCursor(Qt::ArrowCursor);
388 }
389
setFormWidgetsController(FormWidgetsController * controller)390 void CheckBoxEdit::setFormWidgetsController(FormWidgetsController *controller)
391 {
392 Okular::FormFieldButton *form = static_cast<Okular::FormFieldButton *>(m_ff);
393 FormWidgetIface::setFormWidgetsController(controller);
394 m_controller->registerRadioButton(this, form);
395 setChecked(form->state());
396 }
397
doActivateAction()398 void CheckBoxEdit::doActivateAction()
399 {
400 Okular::FormFieldButton *form = static_cast<Okular::FormFieldButton *>(m_ff);
401 if (form->activationAction())
402 m_controller->signalAction(form->activationAction());
403 }
404
slotRefresh(Okular::FormField * form)405 void CheckBoxEdit::slotRefresh(Okular::FormField *form)
406 {
407 if (form != m_ff) {
408 return;
409 }
410 FormWidgetIface::slotRefresh(form);
411
412 Okular::FormFieldButton *button = static_cast<Okular::FormFieldButton *>(m_ff);
413 bool oldState = isChecked();
414 bool newState = button->state();
415 if (oldState != newState) {
416 setChecked(button->state());
417 doActivateAction();
418 }
419 }
420
RadioButtonEdit(Okular::FormFieldButton * button,QWidget * parent)421 RadioButtonEdit::RadioButtonEdit(Okular::FormFieldButton *button, QWidget *parent)
422 : QRadioButton(parent)
423 , FormWidgetIface(this, button)
424 {
425 setText(button->caption());
426
427 setVisible(button->isVisible());
428 setCursor(Qt::ArrowCursor);
429 }
430
setFormWidgetsController(FormWidgetsController * controller)431 void RadioButtonEdit::setFormWidgetsController(FormWidgetsController *controller)
432 {
433 Okular::FormFieldButton *form = static_cast<Okular::FormFieldButton *>(m_ff);
434 FormWidgetIface::setFormWidgetsController(controller);
435 m_controller->registerRadioButton(this, form);
436 setChecked(form->state());
437 }
438
FormLineEdit(Okular::FormFieldText * text,QWidget * parent)439 FormLineEdit::FormLineEdit(Okular::FormFieldText *text, QWidget *parent)
440 : QLineEdit(parent)
441 , FormWidgetIface(this, text)
442 {
443 int maxlen = text->maximumLength();
444 if (maxlen >= 0)
445 setMaxLength(maxlen);
446 setAlignment(text->textAlignment());
447 setText(text->text());
448 if (text->isPassword())
449 setEchoMode(QLineEdit::Password);
450
451 m_prevCursorPos = cursorPosition();
452 m_prevAnchorPos = cursorPosition();
453 m_editing = false;
454
455 connect(this, &QLineEdit::textEdited, this, &FormLineEdit::slotChanged);
456 connect(this, &QLineEdit::cursorPositionChanged, this, &FormLineEdit::slotChanged);
457
458 setVisible(text->isVisible());
459 }
460
setFormWidgetsController(FormWidgetsController * controller)461 void FormLineEdit::setFormWidgetsController(FormWidgetsController *controller)
462 {
463 FormWidgetIface::setFormWidgetsController(controller);
464 connect(m_controller, &FormWidgetsController::formTextChangedByUndoRedo, this, &FormLineEdit::slotHandleTextChangedByUndoRedo);
465 }
466
event(QEvent * e)467 bool FormLineEdit::event(QEvent *e)
468 {
469 if (e->type() == QEvent::KeyPress) {
470 QKeyEvent *keyEvent = static_cast<QKeyEvent *>(e);
471 if (keyEvent == QKeySequence::Undo) {
472 emit m_controller->requestUndo();
473 return true;
474 } else if (keyEvent == QKeySequence::Redo) {
475 emit m_controller->requestRedo();
476 return true;
477 }
478 } else if (e->type() == QEvent::FocusIn) {
479 const auto fft = static_cast<Okular::FormFieldText *>(m_ff);
480 if (text() != fft->text())
481 setText(fft->text());
482 m_editing = true;
483
484 QFocusEvent *focusEvent = static_cast<QFocusEvent *>(e);
485 if (focusEvent->reason() != Qt::ActiveWindowFocusReason) {
486 if (const Okular::Action *action = m_ff->additionalAction(Okular::Annotation::FocusIn))
487 emit m_controller->focusAction(action, fft);
488 }
489 setFocus();
490 } else if (e->type() == QEvent::FocusOut) {
491 m_editing = false;
492
493 // Don't worry about focus events from other sources than the user FocusEvent to edit the field
494 QFocusEvent *focusEvent = static_cast<QFocusEvent *>(e);
495 if (focusEvent->reason() == Qt::OtherFocusReason || focusEvent->reason() == Qt::ActiveWindowFocusReason)
496 return true;
497
498 if (const Okular::Action *action = m_ff->additionalAction(Okular::Annotation::FocusOut)) {
499 bool ok = false;
500 emit m_controller->validateAction(action, static_cast<Okular::FormFieldText *>(m_ff), ok);
501 }
502 if (const Okular::Action *action = m_ff->additionalAction(Okular::FormField::FormatField)) {
503 emit m_controller->formatAction(action, static_cast<Okular::FormFieldText *>(m_ff));
504 }
505 }
506 return QLineEdit::event(e);
507 }
508
contextMenuEvent(QContextMenuEvent * event)509 void FormLineEdit::contextMenuEvent(QContextMenuEvent *event)
510 {
511 QMenu *menu = createStandardContextMenu();
512
513 QList<QAction *> actionList = menu->actions();
514 enum { UndoAct, RedoAct, CutAct, CopyAct, PasteAct, DeleteAct, SelectAllAct };
515
516 QAction *kundo = KStandardAction::create(KStandardAction::Undo, m_controller, SIGNAL(requestUndo()), menu);
517 QAction *kredo = KStandardAction::create(KStandardAction::Redo, m_controller, SIGNAL(requestRedo()), menu);
518 connect(m_controller, &FormWidgetsController::canUndoChanged, kundo, &QAction::setEnabled);
519 connect(m_controller, &FormWidgetsController::canRedoChanged, kredo, &QAction::setEnabled);
520 kundo->setEnabled(m_controller->canUndo());
521 kredo->setEnabled(m_controller->canRedo());
522
523 QAction *oldUndo, *oldRedo;
524 oldUndo = actionList[UndoAct];
525 oldRedo = actionList[RedoAct];
526
527 menu->insertAction(oldUndo, kundo);
528 menu->insertAction(oldRedo, kredo);
529
530 menu->removeAction(oldUndo);
531 menu->removeAction(oldRedo);
532
533 menu->exec(event->globalPos());
534 delete menu;
535 }
536
slotChanged()537 void FormLineEdit::slotChanged()
538 {
539 Okular::FormFieldText *form = static_cast<Okular::FormFieldText *>(m_ff);
540 QString contents = text();
541 int cursorPos = cursorPosition();
542
543 if (form->additionalAction(Okular::FormField::FieldModified) && m_editing && !form->isReadOnly()) {
544 bool ok = false;
545 QString oldInputText = form->text();
546 form->setText(text());
547 emit m_controller->keystrokeAction(form->additionalAction(Okular::FormField::FieldModified), form, ok);
548 form->setText(oldInputText);
549 if (!ok) {
550 setText(oldInputText);
551 return;
552 }
553 }
554
555 if (contents != form->text()) {
556 emit m_controller->formTextChangedByWidget(pageItem()->pageNumber(), form, contents, cursorPos, m_prevCursorPos, m_prevAnchorPos);
557 }
558
559 m_prevCursorPos = cursorPos;
560 m_prevAnchorPos = cursorPos;
561 if (hasSelectedText()) {
562 if (cursorPos == selectionStart()) {
563 m_prevAnchorPos = selectionStart() + selectedText().size();
564 } else {
565 m_prevAnchorPos = selectionStart();
566 }
567 }
568 }
569
slotHandleTextChangedByUndoRedo(int pageNumber,Okular::FormFieldText * textForm,const QString & contents,int cursorPos,int anchorPos)570 void FormLineEdit::slotHandleTextChangedByUndoRedo(int pageNumber, Okular::FormFieldText *textForm, const QString &contents, int cursorPos, int anchorPos)
571 {
572 Q_UNUSED(pageNumber);
573 if (textForm != m_ff || contents == text()) {
574 return;
575 }
576 disconnect(this, &QLineEdit::cursorPositionChanged, this, &FormLineEdit::slotChanged);
577 setText(contents);
578 setCursorPosition(anchorPos);
579 cursorForward(true, cursorPos - anchorPos);
580 connect(this, &QLineEdit::cursorPositionChanged, this, &FormLineEdit::slotChanged);
581 m_prevCursorPos = cursorPos;
582 m_prevAnchorPos = anchorPos;
583 setFocus();
584 }
585
slotRefresh(Okular::FormField * form)586 void FormLineEdit::slotRefresh(Okular::FormField *form)
587 {
588 if (form != m_ff) {
589 return;
590 }
591 FormWidgetIface::slotRefresh(form);
592
593 Okular::FormFieldText *text = static_cast<Okular::FormFieldText *>(form);
594 setText(text->text());
595 }
596
TextAreaEdit(Okular::FormFieldText * text,QWidget * parent)597 TextAreaEdit::TextAreaEdit(Okular::FormFieldText *text, QWidget *parent)
598 : KTextEdit(parent)
599 , FormWidgetIface(this, text)
600 {
601 setAcceptRichText(text->isRichText());
602 setCheckSpellingEnabled(text->canBeSpellChecked());
603 setAlignment(text->textAlignment());
604 setPlainText(text->text());
605 setUndoRedoEnabled(false);
606
607 connect(this, &QTextEdit::textChanged, this, &TextAreaEdit::slotChanged);
608 connect(this, &QTextEdit::cursorPositionChanged, this, &TextAreaEdit::slotChanged);
609 connect(this, &KTextEdit::aboutToShowContextMenu, this, &TextAreaEdit::slotUpdateUndoAndRedoInContextMenu);
610 m_prevCursorPos = textCursor().position();
611 m_prevAnchorPos = textCursor().anchor();
612 m_editing = false;
613 setVisible(text->isVisible());
614 }
615
~TextAreaEdit()616 TextAreaEdit::~TextAreaEdit()
617 {
618 // We need this because otherwise on destruction we destruct the syntax highlighter
619 // that ends up calling text changed but then we go to slotChanged and we're already
620 // half destructed and all is bad
621 disconnect(this, &QTextEdit::textChanged, this, &TextAreaEdit::slotChanged);
622 }
623
event(QEvent * e)624 bool TextAreaEdit::event(QEvent *e)
625 {
626 if (e->type() == QEvent::KeyPress) {
627 QKeyEvent *keyEvent = static_cast<QKeyEvent *>(e);
628 if (keyEvent == QKeySequence::Undo) {
629 emit m_controller->requestUndo();
630 return true;
631 } else if (keyEvent == QKeySequence::Redo) {
632 emit m_controller->requestRedo();
633 return true;
634 }
635 } else if (e->type() == QEvent::FocusIn) {
636 const auto fft = static_cast<Okular::FormFieldText *>(m_ff);
637 if (toPlainText() != fft->text())
638 setText(fft->text());
639 m_editing = true;
640 } else if (e->type() == QEvent::FocusOut) {
641 m_editing = false;
642 if (const Okular::Action *action = m_ff->additionalAction(Okular::FormField::FormatField)) {
643 emit m_controller->formatAction(action, static_cast<Okular::FormFieldText *>(m_ff));
644 }
645 }
646 return KTextEdit::event(e);
647 }
648
slotUpdateUndoAndRedoInContextMenu(QMenu * menu)649 void TextAreaEdit::slotUpdateUndoAndRedoInContextMenu(QMenu *menu)
650 {
651 if (!menu)
652 return;
653
654 QList<QAction *> actionList = menu->actions();
655 enum { UndoAct, RedoAct, CutAct, CopyAct, PasteAct, ClearAct, SelectAllAct, NCountActs };
656
657 QAction *kundo = KStandardAction::create(KStandardAction::Undo, m_controller, SIGNAL(requestUndo()), menu);
658 QAction *kredo = KStandardAction::create(KStandardAction::Redo, m_controller, SIGNAL(requestRedo()), menu);
659 connect(m_controller, &FormWidgetsController::canUndoChanged, kundo, &QAction::setEnabled);
660 connect(m_controller, &FormWidgetsController::canRedoChanged, kredo, &QAction::setEnabled);
661 kundo->setEnabled(m_controller->canUndo());
662 kredo->setEnabled(m_controller->canRedo());
663
664 QAction *oldUndo, *oldRedo;
665 oldUndo = actionList[UndoAct];
666 oldRedo = actionList[RedoAct];
667
668 menu->insertAction(oldUndo, kundo);
669 menu->insertAction(oldRedo, kredo);
670
671 menu->removeAction(oldUndo);
672 menu->removeAction(oldRedo);
673 }
674
setFormWidgetsController(FormWidgetsController * controller)675 void TextAreaEdit::setFormWidgetsController(FormWidgetsController *controller)
676 {
677 FormWidgetIface::setFormWidgetsController(controller);
678 connect(m_controller, &FormWidgetsController::formTextChangedByUndoRedo, this, &TextAreaEdit::slotHandleTextChangedByUndoRedo);
679 }
680
slotHandleTextChangedByUndoRedo(int pageNumber,Okular::FormFieldText * textForm,const QString & contents,int cursorPos,int anchorPos)681 void TextAreaEdit::slotHandleTextChangedByUndoRedo(int pageNumber, Okular::FormFieldText *textForm, const QString &contents, int cursorPos, int anchorPos)
682 {
683 Q_UNUSED(pageNumber);
684 if (textForm != m_ff) {
685 return;
686 }
687 setPlainText(contents);
688 QTextCursor c = textCursor();
689 c.setPosition(anchorPos);
690 c.setPosition(cursorPos, QTextCursor::KeepAnchor);
691 m_prevCursorPos = cursorPos;
692 m_prevAnchorPos = anchorPos;
693 setTextCursor(c);
694 setFocus();
695 }
696
slotChanged()697 void TextAreaEdit::slotChanged()
698 {
699 Okular::FormFieldText *form = static_cast<Okular::FormFieldText *>(m_ff);
700 QString contents = toPlainText();
701 int cursorPos = textCursor().position();
702
703 if (form->additionalAction(Okular::FormField::FieldModified) && m_editing && !form->isReadOnly()) {
704 bool ok = false;
705 QString oldInputText = form->text();
706 form->setText(toPlainText());
707 emit m_controller->keystrokeAction(form->additionalAction(Okular::FormField::FieldModified), form, ok);
708 form->setText(oldInputText);
709 if (!ok) {
710 setText(oldInputText);
711 return;
712 }
713 }
714
715 if (contents != form->text()) {
716 emit m_controller->formTextChangedByWidget(pageItem()->pageNumber(), form, contents, cursorPos, m_prevCursorPos, m_prevAnchorPos);
717 }
718 m_prevCursorPos = cursorPos;
719 m_prevAnchorPos = textCursor().anchor();
720 }
721
slotRefresh(Okular::FormField * form)722 void TextAreaEdit::slotRefresh(Okular::FormField *form)
723 {
724 if (form != m_ff) {
725 return;
726 }
727 FormWidgetIface::slotRefresh(form);
728
729 Okular::FormFieldText *text = static_cast<Okular::FormFieldText *>(form);
730 setPlainText(text->text());
731 }
732
FileEdit(Okular::FormFieldText * text,QWidget * parent)733 FileEdit::FileEdit(Okular::FormFieldText *text, QWidget *parent)
734 : KUrlRequester(parent)
735 , FormWidgetIface(this, text)
736 {
737 setMode(KFile::File | KFile::ExistingOnly | KFile::LocalOnly);
738 setFilter(i18n("*|All Files"));
739 setUrl(QUrl::fromUserInput(text->text()));
740 lineEdit()->setAlignment(text->textAlignment());
741
742 m_prevCursorPos = lineEdit()->cursorPosition();
743 m_prevAnchorPos = lineEdit()->cursorPosition();
744
745 connect(this, &KUrlRequester::textChanged, this, &FileEdit::slotChanged);
746 connect(lineEdit(), &QLineEdit::cursorPositionChanged, this, &FileEdit::slotChanged);
747 setVisible(text->isVisible());
748 }
749
setFormWidgetsController(FormWidgetsController * controller)750 void FileEdit::setFormWidgetsController(FormWidgetsController *controller)
751 {
752 FormWidgetIface::setFormWidgetsController(controller);
753 connect(m_controller, &FormWidgetsController::formTextChangedByUndoRedo, this, &FileEdit::slotHandleFileChangedByUndoRedo);
754 }
755
eventFilter(QObject * obj,QEvent * event)756 bool FileEdit::eventFilter(QObject *obj, QEvent *event)
757 {
758 if (obj == lineEdit()) {
759 if (event->type() == QEvent::KeyPress) {
760 QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
761 if (keyEvent == QKeySequence::Undo) {
762 emit m_controller->requestUndo();
763 return true;
764 } else if (keyEvent == QKeySequence::Redo) {
765 emit m_controller->requestRedo();
766 return true;
767 }
768 } else if (event->type() == QEvent::ContextMenu) {
769 QContextMenuEvent *contextMenuEvent = static_cast<QContextMenuEvent *>(event);
770
771 QMenu *menu = ((QLineEdit *)lineEdit())->createStandardContextMenu();
772
773 QList<QAction *> actionList = menu->actions();
774 enum { UndoAct, RedoAct, CutAct, CopyAct, PasteAct, DeleteAct, SelectAllAct };
775
776 QAction *kundo = KStandardAction::create(KStandardAction::Undo, m_controller, SIGNAL(requestUndo()), menu);
777 QAction *kredo = KStandardAction::create(KStandardAction::Redo, m_controller, SIGNAL(requestRedo()), menu);
778 connect(m_controller, &FormWidgetsController::canUndoChanged, kundo, &QAction::setEnabled);
779 connect(m_controller, &FormWidgetsController::canRedoChanged, kredo, &QAction::setEnabled);
780 kundo->setEnabled(m_controller->canUndo());
781 kredo->setEnabled(m_controller->canRedo());
782
783 QAction *oldUndo, *oldRedo;
784 oldUndo = actionList[UndoAct];
785 oldRedo = actionList[RedoAct];
786
787 menu->insertAction(oldUndo, kundo);
788 menu->insertAction(oldRedo, kredo);
789
790 menu->removeAction(oldUndo);
791 menu->removeAction(oldRedo);
792
793 menu->exec(contextMenuEvent->globalPos());
794 delete menu;
795 return true;
796 }
797 }
798 return KUrlRequester::eventFilter(obj, event);
799 }
800
slotChanged()801 void FileEdit::slotChanged()
802 {
803 // Make sure line edit's text matches url expansion
804 if (text() != url().toLocalFile())
805 this->setText(url().toLocalFile());
806
807 Okular::FormFieldText *form = static_cast<Okular::FormFieldText *>(m_ff);
808
809 QString contents = text();
810 int cursorPos = lineEdit()->cursorPosition();
811 if (contents != form->text()) {
812 emit m_controller->formTextChangedByWidget(pageItem()->pageNumber(), form, contents, cursorPos, m_prevCursorPos, m_prevAnchorPos);
813 }
814
815 m_prevCursorPos = cursorPos;
816 m_prevAnchorPos = cursorPos;
817 if (lineEdit()->hasSelectedText()) {
818 if (cursorPos == lineEdit()->selectionStart()) {
819 m_prevAnchorPos = lineEdit()->selectionStart() + lineEdit()->selectedText().size();
820 } else {
821 m_prevAnchorPos = lineEdit()->selectionStart();
822 }
823 }
824 }
825
slotHandleFileChangedByUndoRedo(int pageNumber,Okular::FormFieldText * form,const QString & contents,int cursorPos,int anchorPos)826 void FileEdit::slotHandleFileChangedByUndoRedo(int pageNumber, Okular::FormFieldText *form, const QString &contents, int cursorPos, int anchorPos)
827 {
828 Q_UNUSED(pageNumber);
829 if (form != m_ff || contents == text()) {
830 return;
831 }
832 disconnect(lineEdit(), &QLineEdit::cursorPositionChanged, this, &FileEdit::slotChanged);
833 setText(contents);
834 lineEdit()->setCursorPosition(anchorPos);
835 lineEdit()->cursorForward(true, cursorPos - anchorPos);
836 connect(lineEdit(), &QLineEdit::cursorPositionChanged, this, &FileEdit::slotChanged);
837 m_prevCursorPos = cursorPos;
838 m_prevAnchorPos = anchorPos;
839 setFocus();
840 }
841
ListEdit(Okular::FormFieldChoice * choice,QWidget * parent)842 ListEdit::ListEdit(Okular::FormFieldChoice *choice, QWidget *parent)
843 : QListWidget(parent)
844 , FormWidgetIface(this, choice)
845 {
846 addItems(choice->choices());
847 setSelectionMode(choice->multiSelect() ? QAbstractItemView::ExtendedSelection : QAbstractItemView::SingleSelection);
848 setVerticalScrollMode(QAbstractItemView::ScrollPerPixel);
849 const QList<int> selectedItems = choice->currentChoices();
850 if (choice->multiSelect()) {
851 for (const int index : selectedItems)
852 if (index >= 0 && index < count())
853 item(index)->setSelected(true);
854 } else {
855 if (selectedItems.count() == 1 && selectedItems.at(0) >= 0 && selectedItems.at(0) < count()) {
856 setCurrentRow(selectedItems.at(0));
857 scrollToItem(item(selectedItems.at(0)));
858 }
859 }
860
861 connect(this, &QListWidget::itemSelectionChanged, this, &ListEdit::slotSelectionChanged);
862
863 setVisible(choice->isVisible());
864 setCursor(Qt::ArrowCursor);
865 }
866
setFormWidgetsController(FormWidgetsController * controller)867 void ListEdit::setFormWidgetsController(FormWidgetsController *controller)
868 {
869 FormWidgetIface::setFormWidgetsController(controller);
870 connect(m_controller, &FormWidgetsController::formListChangedByUndoRedo, this, &ListEdit::slotHandleFormListChangedByUndoRedo);
871 }
872
slotSelectionChanged()873 void ListEdit::slotSelectionChanged()
874 {
875 const QList<QListWidgetItem *> selection = selectedItems();
876 QList<int> rows;
877 for (const QListWidgetItem *item : selection) {
878 rows.append(row(item));
879 }
880 Okular::FormFieldChoice *form = static_cast<Okular::FormFieldChoice *>(m_ff);
881 if (rows != form->currentChoices()) {
882 emit m_controller->formListChangedByWidget(pageItem()->pageNumber(), form, rows);
883 }
884 }
885
slotHandleFormListChangedByUndoRedo(int pageNumber,Okular::FormFieldChoice * listForm,const QList<int> & choices)886 void ListEdit::slotHandleFormListChangedByUndoRedo(int pageNumber, Okular::FormFieldChoice *listForm, const QList<int> &choices)
887 {
888 Q_UNUSED(pageNumber);
889
890 if (m_ff != listForm) {
891 return;
892 }
893
894 disconnect(this, &QListWidget::itemSelectionChanged, this, &ListEdit::slotSelectionChanged);
895 for (int i = 0; i < count(); i++) {
896 item(i)->setSelected(choices.contains(i));
897 }
898 connect(this, &QListWidget::itemSelectionChanged, this, &ListEdit::slotSelectionChanged);
899
900 setFocus();
901 }
902
ComboEdit(Okular::FormFieldChoice * choice,QWidget * parent)903 ComboEdit::ComboEdit(Okular::FormFieldChoice *choice, QWidget *parent)
904 : QComboBox(parent)
905 , FormWidgetIface(this, choice)
906 {
907 addItems(choice->choices());
908 setEditable(true);
909 setInsertPolicy(NoInsert);
910 lineEdit()->setReadOnly(!choice->isEditable());
911 QList<int> selectedItems = choice->currentChoices();
912 if (selectedItems.count() == 1 && selectedItems.at(0) >= 0 && selectedItems.at(0) < count())
913 setCurrentIndex(selectedItems.at(0));
914
915 if (choice->isEditable() && !choice->editChoice().isEmpty())
916 lineEdit()->setText(choice->editChoice());
917
918 connect(this, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &ComboEdit::slotValueChanged);
919 connect(this, &QComboBox::editTextChanged, this, &ComboEdit::slotValueChanged);
920 connect(lineEdit(), &QLineEdit::cursorPositionChanged, this, &ComboEdit::slotValueChanged);
921
922 setVisible(choice->isVisible());
923 setCursor(Qt::ArrowCursor);
924 m_prevCursorPos = lineEdit()->cursorPosition();
925 m_prevAnchorPos = lineEdit()->cursorPosition();
926 }
927
setFormWidgetsController(FormWidgetsController * controller)928 void ComboEdit::setFormWidgetsController(FormWidgetsController *controller)
929 {
930 FormWidgetIface::setFormWidgetsController(controller);
931 connect(m_controller, &FormWidgetsController::formComboChangedByUndoRedo, this, &ComboEdit::slotHandleFormComboChangedByUndoRedo);
932 }
933
slotValueChanged()934 void ComboEdit::slotValueChanged()
935 {
936 const QString text = lineEdit()->text();
937
938 Okular::FormFieldChoice *form = static_cast<Okular::FormFieldChoice *>(m_ff);
939
940 QString prevText;
941 if (form->currentChoices().isEmpty()) {
942 prevText = form->editChoice();
943 } else {
944 prevText = form->choices().at(form->currentChoices().constFirst());
945 }
946
947 int cursorPos = lineEdit()->cursorPosition();
948 if (text != prevText) {
949 emit m_controller->formComboChangedByWidget(pageItem()->pageNumber(), form, currentText(), cursorPos, m_prevCursorPos, m_prevAnchorPos);
950 }
951 prevText = text;
952 m_prevCursorPos = cursorPos;
953 m_prevAnchorPos = cursorPos;
954 if (lineEdit()->hasSelectedText()) {
955 if (cursorPos == lineEdit()->selectionStart()) {
956 m_prevAnchorPos = lineEdit()->selectionStart() + lineEdit()->selectedText().size();
957 } else {
958 m_prevAnchorPos = lineEdit()->selectionStart();
959 }
960 }
961 }
962
slotHandleFormComboChangedByUndoRedo(int pageNumber,Okular::FormFieldChoice * form,const QString & text,int cursorPos,int anchorPos)963 void ComboEdit::slotHandleFormComboChangedByUndoRedo(int pageNumber, Okular::FormFieldChoice *form, const QString &text, int cursorPos, int anchorPos)
964 {
965 Q_UNUSED(pageNumber);
966
967 if (m_ff != form) {
968 return;
969 }
970
971 // Determine if text corrisponds to an index choices
972 int index = -1;
973 for (int i = 0; i < count(); i++) {
974 if (itemText(i) == text) {
975 index = i;
976 }
977 }
978
979 m_prevCursorPos = cursorPos;
980 m_prevAnchorPos = anchorPos;
981
982 disconnect(lineEdit(), &QLineEdit::cursorPositionChanged, this, &ComboEdit::slotValueChanged);
983 const bool isCustomValue = index == -1;
984 if (isCustomValue) {
985 setEditText(text);
986 } else {
987 setCurrentIndex(index);
988 }
989 lineEdit()->setCursorPosition(anchorPos);
990 lineEdit()->cursorForward(true, cursorPos - anchorPos);
991 connect(lineEdit(), &QLineEdit::cursorPositionChanged, this, &ComboEdit::slotValueChanged);
992 setFocus();
993 }
994
contextMenuEvent(QContextMenuEvent * event)995 void ComboEdit::contextMenuEvent(QContextMenuEvent *event)
996 {
997 QMenu *menu = lineEdit()->createStandardContextMenu();
998
999 QList<QAction *> actionList = menu->actions();
1000 enum { UndoAct, RedoAct, CutAct, CopyAct, PasteAct, DeleteAct, SelectAllAct };
1001
1002 QAction *kundo = KStandardAction::create(KStandardAction::Undo, m_controller, SIGNAL(requestUndo()), menu);
1003 QAction *kredo = KStandardAction::create(KStandardAction::Redo, m_controller, SIGNAL(requestRedo()), menu);
1004 connect(m_controller, &FormWidgetsController::canUndoChanged, kundo, &QAction::setEnabled);
1005 connect(m_controller, &FormWidgetsController::canRedoChanged, kredo, &QAction::setEnabled);
1006 kundo->setEnabled(m_controller->canUndo());
1007 kredo->setEnabled(m_controller->canRedo());
1008
1009 QAction *oldUndo, *oldRedo;
1010 oldUndo = actionList[UndoAct];
1011 oldRedo = actionList[RedoAct];
1012
1013 menu->insertAction(oldUndo, kundo);
1014 menu->insertAction(oldRedo, kredo);
1015
1016 menu->removeAction(oldUndo);
1017 menu->removeAction(oldRedo);
1018
1019 menu->exec(event->globalPos());
1020 delete menu;
1021 }
1022
event(QEvent * e)1023 bool ComboEdit::event(QEvent *e)
1024 {
1025 if (e->type() == QEvent::KeyPress) {
1026 QKeyEvent *keyEvent = static_cast<QKeyEvent *>(e);
1027 if (keyEvent == QKeySequence::Undo) {
1028 emit m_controller->requestUndo();
1029 return true;
1030 } else if (keyEvent == QKeySequence::Redo) {
1031 emit m_controller->requestRedo();
1032 return true;
1033 }
1034 }
1035 return QComboBox::event(e);
1036 }
1037
SignatureEdit(Okular::FormFieldSignature * signature,QWidget * parent)1038 SignatureEdit::SignatureEdit(Okular::FormFieldSignature *signature, QWidget *parent)
1039 : QAbstractButton(parent)
1040 , FormWidgetIface(this, signature)
1041 , m_widgetPressed(false)
1042 , m_dummyMode(false)
1043 , m_wasVisible(false)
1044 {
1045 setCursor(Qt::PointingHandCursor);
1046 connect(this, &SignatureEdit::clicked, this, &SignatureEdit::slotViewProperties);
1047 }
1048
setDummyMode(bool set)1049 void SignatureEdit::setDummyMode(bool set)
1050 {
1051 m_dummyMode = set;
1052 if (m_dummyMode) {
1053 m_wasVisible = isVisible();
1054 // if widget was hidden then show it.
1055 // even if it wasn't hidden calling this will still update the background.
1056 setVisibility(true);
1057 } else {
1058 // forms were not visible before this call so hide this widget.
1059 if (!m_wasVisible)
1060 setVisibility(false);
1061 // forms were visible even before this call so only update the background color.
1062 else
1063 update();
1064 }
1065 }
1066
event(QEvent * e)1067 bool SignatureEdit::event(QEvent *e)
1068 {
1069 if (m_dummyMode && e->type() != QEvent::Paint) {
1070 e->accept();
1071 return true;
1072 }
1073
1074 switch (e->type()) {
1075 case QEvent::MouseButtonPress: {
1076 QMouseEvent *ev = static_cast<QMouseEvent *>(e);
1077 if (ev->button() == Qt::LeftButton) {
1078 m_widgetPressed = true;
1079 update();
1080 }
1081 break;
1082 }
1083 case QEvent::MouseButtonRelease: {
1084 QMouseEvent *ev = static_cast<QMouseEvent *>(e);
1085 if (ev->button() == Qt::LeftButton) {
1086 m_widgetPressed = false;
1087 update();
1088 }
1089 break;
1090 }
1091 case QEvent::Leave: {
1092 m_widgetPressed = false;
1093 update();
1094 }
1095 default:
1096 break;
1097 }
1098
1099 return QAbstractButton::event(e);
1100 }
1101
contextMenuEvent(QContextMenuEvent * event)1102 void SignatureEdit::contextMenuEvent(QContextMenuEvent *event)
1103 {
1104 QMenu *menu = new QMenu(this);
1105 QAction *signatureProperties = new QAction(i18n("Signature Properties"), menu);
1106 connect(signatureProperties, &QAction::triggered, this, &SignatureEdit::slotViewProperties);
1107 menu->addAction(signatureProperties);
1108 menu->exec(event->globalPos());
1109 delete menu;
1110 }
1111
paintEvent(QPaintEvent *)1112 void SignatureEdit::paintEvent(QPaintEvent *)
1113 {
1114 QPainter painter(this);
1115 // no borders when user hasn't allowed the forms to be shown
1116 if (m_dummyMode && !m_wasVisible) {
1117 painter.setPen(Qt::transparent);
1118 } else {
1119 painter.setPen(Qt::black);
1120 }
1121
1122 if (m_widgetPressed || m_dummyMode) {
1123 QColor col = palette().color(QPalette::Active, QPalette::Highlight);
1124 col.setAlpha(50);
1125 painter.setBrush(col);
1126 } else {
1127 painter.setBrush(Qt::transparent);
1128 }
1129 painter.drawRect(0, 0, width() - 2, height() - 2);
1130 }
1131
slotViewProperties()1132 void SignatureEdit::slotViewProperties()
1133 {
1134 if (m_dummyMode)
1135 return;
1136
1137 Okular::FormFieldSignature *formSignature = static_cast<Okular::FormFieldSignature *>(formField());
1138 SignaturePropertiesDialog propDlg(m_controller->m_doc, formSignature, this);
1139 propDlg.exec();
1140 }
1141
1142 // Code for additional action handling.
1143 // Challenge: Change preprocessor magic to C++ magic!
1144 //
1145 // The mouseRelease event is special because the PDF spec
1146 // says that the activation action takes precedence over this.
1147 // So the mouse release action is only signaled if no activation
1148 // action exists.
1149 //
1150 // For checkboxes the activation action is not triggered as
1151 // they are still triggered from the clicked signal and additionally
1152 // when the checked state changes.
1153
1154 #define DEFINE_ADDITIONAL_ACTIONS(FormClass, BaseClass) \
1155 void FormClass::mousePressEvent(QMouseEvent *event) \
1156 { \
1157 Okular::Action *act = m_ff->additionalAction(Okular::Annotation::MousePressed); \
1158 if (act) { \
1159 m_controller->signalAction(act); \
1160 } \
1161 BaseClass::mousePressEvent(event); \
1162 } \
1163 void FormClass::mouseReleaseEvent(QMouseEvent *event) \
1164 { \
1165 if (!QWidget::rect().contains(event->localPos().toPoint())) { \
1166 BaseClass::mouseReleaseEvent(event); \
1167 return; \
1168 } \
1169 Okular::Action *act = m_ff->activationAction(); \
1170 if (act && !qobject_cast<CheckBoxEdit *>(this)) { \
1171 m_controller->signalAction(act); \
1172 } else if ((act = m_ff->additionalAction(Okular::Annotation::MouseReleased))) { \
1173 m_controller->signalAction(act); \
1174 } \
1175 BaseClass::mouseReleaseEvent(event); \
1176 } \
1177 void FormClass::focusInEvent(QFocusEvent *event) \
1178 { \
1179 Okular::Action *act = m_ff->additionalAction(Okular::Annotation::FocusIn); \
1180 if (act) { \
1181 m_controller->processScriptAction(act, m_ff, Okular::Annotation::FocusIn); \
1182 } \
1183 BaseClass::focusInEvent(event); \
1184 } \
1185 void FormClass::focusOutEvent(QFocusEvent *event) \
1186 { \
1187 Okular::Action *act = m_ff->additionalAction(Okular::Annotation::FocusOut); \
1188 if (act) { \
1189 m_controller->processScriptAction(act, m_ff, Okular::Annotation::FocusOut); \
1190 } \
1191 BaseClass::focusOutEvent(event); \
1192 } \
1193 void FormClass::leaveEvent(QEvent *event) \
1194 { \
1195 Okular::Action *act = m_ff->additionalAction(Okular::Annotation::CursorLeaving); \
1196 if (act) { \
1197 m_controller->signalAction(act); \
1198 } \
1199 BaseClass::leaveEvent(event); \
1200 } \
1201 void FormClass::enterEvent(QEvent *event) \
1202 { \
1203 Okular::Action *act = m_ff->additionalAction(Okular::Annotation::CursorEntering); \
1204 if (act) { \
1205 m_controller->signalAction(act); \
1206 } \
1207 BaseClass::enterEvent(event); \
1208 }
1209
1210 DEFINE_ADDITIONAL_ACTIONS(PushButtonEdit, QPushButton)
1211 DEFINE_ADDITIONAL_ACTIONS(CheckBoxEdit, QCheckBox)
1212 DEFINE_ADDITIONAL_ACTIONS(RadioButtonEdit, QRadioButton)
1213 DEFINE_ADDITIONAL_ACTIONS(FormLineEdit, QLineEdit)
1214 DEFINE_ADDITIONAL_ACTIONS(TextAreaEdit, KTextEdit)
1215 DEFINE_ADDITIONAL_ACTIONS(FileEdit, KUrlRequester)
1216 DEFINE_ADDITIONAL_ACTIONS(ListEdit, QListWidget)
1217 DEFINE_ADDITIONAL_ACTIONS(ComboEdit, QComboBox)
1218 DEFINE_ADDITIONAL_ACTIONS(SignatureEdit, QAbstractButton)
1219
1220 #undef DEFINE_ADDITIONAL_ACTIONS
1221