Okular

documentcommands.cpp
1/*
2 SPDX-FileCopyrightText: 2013 Jon Mease <jon.mease@gmail.com>
3
4 Work sponsored by the LiMux project of the city of Munich:
5 SPDX-FileCopyrightText: 2017 Klarälvdalens Datakonsult AB a KDAB Group company <info@kdab.com>
6
7 SPDX-License-Identifier: GPL-2.0-or-later
8*/
9
10#include "documentcommands_p.h"
11
12#include "annotations.h"
13#include "debug_p.h"
14#include "document_p.h"
15#include "form.h"
16#include "page.h"
17#include "page_p.h"
18#include "utils_p.h"
19
20#include <KLocalizedString>
21
22namespace Okular
23{
24void moveViewportIfBoundingRectNotFullyVisible(Okular::NormalizedRect boundingRect, DocumentPrivate *docPriv, int pageNumber)
25{
26 const Rotation pageRotation = docPriv->m_parent->page(pageNumber)->rotation();
27 const QTransform rotationMatrix = Okular::buildRotationMatrix(pageRotation);
28 boundingRect.transform(rotationMatrix);
29 if (!docPriv->isNormalizedRectangleFullyVisible(boundingRect, pageNumber)) {
30 DocumentViewport searchViewport(pageNumber);
31 searchViewport.rePos.enabled = true;
32 searchViewport.rePos.normalizedX = (boundingRect.left + boundingRect.right) / 2.0;
33 searchViewport.rePos.normalizedY = (boundingRect.top + boundingRect.bottom) / 2.0;
34 docPriv->m_parent->setViewport(searchViewport, nullptr, true);
35 }
36}
37
38Okular::NormalizedRect buildBoundingRectangleForButtons(const QList<Okular::FormFieldButton *> &formButtons)
39{
40 // Initialize coordinates of the bounding rect
41 double left = 1.0;
42 double top = 1.0;
43 double right = 0.0;
44 double bottom = 0.0;
45
46 for (const FormFieldButton *formButton : formButtons) {
47 left = qMin<double>(left, formButton->rect().left);
48 top = qMin<double>(top, formButton->rect().top);
49 right = qMax<double>(right, formButton->rect().right);
50 bottom = qMax<double>(bottom, formButton->rect().bottom);
51 }
52 Okular::NormalizedRect boundingRect(left, top, right, bottom);
53 return boundingRect;
54}
55
56AddAnnotationCommand::AddAnnotationCommand(Okular::DocumentPrivate *docPriv, Okular::Annotation *annotation, int pageNumber)
57 : m_docPriv(docPriv)
58 , m_annotation(annotation)
59 , m_pageNumber(pageNumber)
60 , m_done(false)
61{
62 setText(i18nc("Add an annotation to the page", "add annotation"));
63}
64
65AddAnnotationCommand::~AddAnnotationCommand()
66{
67 if (!m_done) {
68 delete m_annotation;
69 }
70}
71
72void AddAnnotationCommand::undo()
73{
74 moveViewportIfBoundingRectNotFullyVisible(m_annotation->boundingRectangle(), m_docPriv, m_pageNumber);
75 m_docPriv->performRemovePageAnnotation(m_pageNumber, m_annotation);
76 m_done = false;
77}
78
79void AddAnnotationCommand::redo()
80{
81 moveViewportIfBoundingRectNotFullyVisible(m_annotation->boundingRectangle(), m_docPriv, m_pageNumber);
82 m_docPriv->performAddPageAnnotation(m_pageNumber, m_annotation);
83 m_done = true;
84}
85
86bool AddAnnotationCommand::refreshInternalPageReferences(const QVector<Okular::Page *> &newPagesVector)
87{
88 if (m_done) {
89 // We don't always update m_annotation because even if the annotation has been added to the document
90 // it can have been removed later so the annotation pointer is stored inside a following RemoveAnnotationCommand
91 // and thus doesn't need updating because it didn't change
92 // because of the document reload
93 auto a = newPagesVector[m_pageNumber]->annotation(m_annotation->uniqueName());
94 if (a) {
95 m_annotation = a;
96 }
97 }
98
99 return true;
100}
101
102RemoveAnnotationCommand::RemoveAnnotationCommand(Okular::DocumentPrivate *doc, Okular::Annotation *annotation, int pageNumber)
103 : m_docPriv(doc)
104 , m_annotation(annotation)
105 , m_pageNumber(pageNumber)
106 , m_done(false)
107{
108 setText(i18nc("Remove an annotation from the page", "remove annotation"));
109}
110
111RemoveAnnotationCommand::~RemoveAnnotationCommand()
112{
113 if (m_done) {
114 delete m_annotation;
115 }
116}
117
118void RemoveAnnotationCommand::undo()
119{
120 moveViewportIfBoundingRectNotFullyVisible(m_annotation->boundingRectangle(), m_docPriv, m_pageNumber);
121 m_docPriv->performAddPageAnnotation(m_pageNumber, m_annotation);
122 m_done = false;
123}
124
125void RemoveAnnotationCommand::redo()
126{
127 moveViewportIfBoundingRectNotFullyVisible(m_annotation->boundingRectangle(), m_docPriv, m_pageNumber);
128 m_docPriv->performRemovePageAnnotation(m_pageNumber, m_annotation);
129 m_done = true;
130}
131
132bool RemoveAnnotationCommand::refreshInternalPageReferences(const QVector<Okular::Page *> &newPagesVector)
133{
134 if (!m_done) {
135 // We don't always update m_annotation because it can happen that the annotation remove has been undo
136 // and that annotation addition has also been undone so the annotation pointer is stored inside
137 // a previous AddAnnotationCommand and thus doesn't need updating because it didn't change
138 // because of the document reload
139 auto a = newPagesVector[m_pageNumber]->annotation(m_annotation->uniqueName());
140 if (a) {
141 m_annotation = a;
142 }
143 }
144
145 return true;
146}
147
148ModifyAnnotationPropertiesCommand::ModifyAnnotationPropertiesCommand(DocumentPrivate *docPriv, Annotation *annotation, int pageNumber, const QDomNode &oldProperties, const QDomNode &newProperties)
149 : m_docPriv(docPriv)
150 , m_annotation(annotation)
151 , m_pageNumber(pageNumber)
152 , m_prevProperties(oldProperties)
153 , m_newProperties(newProperties)
154{
155 setText(i18nc("Modify an annotation's internal properties (Color, line-width, etc.)", "modify annotation properties"));
156}
157
158void ModifyAnnotationPropertiesCommand::undo()
159{
160 moveViewportIfBoundingRectNotFullyVisible(m_annotation->boundingRectangle(), m_docPriv, m_pageNumber);
161 m_annotation->setAnnotationProperties(m_prevProperties);
162 m_docPriv->performModifyPageAnnotation(m_pageNumber, m_annotation, true);
163}
164
165void ModifyAnnotationPropertiesCommand::redo()
166{
167 moveViewportIfBoundingRectNotFullyVisible(m_annotation->boundingRectangle(), m_docPriv, m_pageNumber);
168 m_annotation->setAnnotationProperties(m_newProperties);
169 m_docPriv->performModifyPageAnnotation(m_pageNumber, m_annotation, true);
170}
171
172bool ModifyAnnotationPropertiesCommand::refreshInternalPageReferences(const QVector<Okular::Page *> &newPagesVector)
173{
174 // Same reason for not unconditionally updating m_annotation, the annotation pointer can be stored in an add/Remove command
175 auto a = newPagesVector[m_pageNumber]->annotation(m_annotation->uniqueName());
176 if (a) {
177 m_annotation = a;
178 }
179
180 return true;
181}
182
183TranslateAnnotationCommand::TranslateAnnotationCommand(DocumentPrivate *docPriv, Annotation *annotation, int pageNumber, const Okular::NormalizedPoint &delta, bool completeDrag)
184 : m_docPriv(docPriv)
185 , m_annotation(annotation)
186 , m_pageNumber(pageNumber)
187 , m_delta(delta)
188 , m_completeDrag(completeDrag)
189{
190 setText(i18nc("Translate an annotation's position on the page", "translate annotation"));
191}
192
193void TranslateAnnotationCommand::undo()
194{
195 moveViewportIfBoundingRectNotFullyVisible(translateBoundingRectangle(minusDelta()), m_docPriv, m_pageNumber);
196 m_annotation->translate(minusDelta());
197 m_docPriv->performModifyPageAnnotation(m_pageNumber, m_annotation, true);
198}
199
200void TranslateAnnotationCommand::redo()
201{
202 moveViewportIfBoundingRectNotFullyVisible(translateBoundingRectangle(m_delta), m_docPriv, m_pageNumber);
203 m_annotation->translate(m_delta);
204 m_docPriv->performModifyPageAnnotation(m_pageNumber, m_annotation, true);
205}
206
207int TranslateAnnotationCommand::id() const
208{
209 return 1;
210}
211
212bool TranslateAnnotationCommand::mergeWith(const QUndoCommand *uc)
213{
214 TranslateAnnotationCommand *tuc = (TranslateAnnotationCommand *)uc;
215
216 if (tuc->m_annotation != m_annotation) {
217 return false;
218 }
219
220 if (m_completeDrag) {
221 return false;
222 }
223 m_delta = Okular::NormalizedPoint(tuc->m_delta.x + m_delta.x, tuc->m_delta.y + m_delta.y);
224 m_completeDrag = tuc->m_completeDrag;
225 return true;
226}
227
228Okular::NormalizedPoint TranslateAnnotationCommand::minusDelta()
229{
230 return Okular::NormalizedPoint(-m_delta.x, -m_delta.y);
231}
232
233Okular::NormalizedRect TranslateAnnotationCommand::translateBoundingRectangle(const Okular::NormalizedPoint &delta)
234{
235 Okular::NormalizedRect annotBoundingRect = m_annotation->boundingRectangle();
236 annotBoundingRect.left = annotBoundingRect.left + delta.x;
237 annotBoundingRect.right = annotBoundingRect.right + delta.x;
238 annotBoundingRect.top = annotBoundingRect.top + delta.y;
239 annotBoundingRect.bottom = annotBoundingRect.bottom + delta.y;
240
241 return annotBoundingRect;
242}
243
244bool TranslateAnnotationCommand::refreshInternalPageReferences(const QVector<Page *> &newPagesVector)
245{
246 // Same reason for not unconditionally updating m_annotation, the annotation pointer can be stored in an add/Remove command
247 auto a = newPagesVector[m_pageNumber]->annotation(m_annotation->uniqueName());
248 if (a) {
249 m_annotation = a;
250 }
251
252 return true;
253}
254
255AdjustAnnotationCommand::AdjustAnnotationCommand(Okular::DocumentPrivate *docPriv, Okular::Annotation *annotation, int pageNumber, const Okular::NormalizedPoint &delta1, const Okular::NormalizedPoint &delta2, bool completeDrag)
256 : m_docPriv(docPriv)
257 , m_annotation(annotation)
258 , m_pageNumber(pageNumber)
259 , m_delta1(delta1)
260 , m_delta2(delta2)
261 , m_completeDrag(completeDrag)
262{
263 setText(i18nc("Change an annotation's size", "adjust annotation"));
264}
265
266void AdjustAnnotationCommand::undo()
267{
268 const NormalizedPoint minusDelta1 = Okular::NormalizedPoint(-m_delta1.x, -m_delta1.y);
269 const NormalizedPoint minusDelta2 = Okular::NormalizedPoint(-m_delta2.x, -m_delta2.y);
270 moveViewportIfBoundingRectNotFullyVisible(adjustBoundingRectangle(minusDelta1, minusDelta2), m_docPriv, m_pageNumber);
271 m_annotation->adjust(minusDelta1, minusDelta2);
272 m_docPriv->performModifyPageAnnotation(m_pageNumber, m_annotation, true);
273}
274
275void AdjustAnnotationCommand::redo()
276{
277 moveViewportIfBoundingRectNotFullyVisible(adjustBoundingRectangle(m_delta1, m_delta2), m_docPriv, m_pageNumber);
278 m_annotation->adjust(m_delta1, m_delta2);
279 m_docPriv->performModifyPageAnnotation(m_pageNumber, m_annotation, true);
280}
281
282int AdjustAnnotationCommand::id() const
283{
284 return 5;
285}
286
287bool AdjustAnnotationCommand::mergeWith(const QUndoCommand *uc)
288{
289 AdjustAnnotationCommand *tuc = (AdjustAnnotationCommand *)uc;
290
291 if (tuc->m_annotation != m_annotation) {
292 return false;
293 }
294
295 if (m_completeDrag) {
296 return false;
297 }
298 m_delta1 = Okular::NormalizedPoint(tuc->m_delta1.x + m_delta1.x, tuc->m_delta1.y + m_delta1.y);
299 m_delta2 = Okular::NormalizedPoint(tuc->m_delta2.x + m_delta2.x, tuc->m_delta2.y + m_delta2.y);
300 m_completeDrag = tuc->m_completeDrag;
301 return true;
302}
303
304Okular::NormalizedRect AdjustAnnotationCommand::adjustBoundingRectangle(const Okular::NormalizedPoint &delta1, const Okular::NormalizedPoint &delta2)
305{
306 Okular::NormalizedRect annotBoundingRect = m_annotation->boundingRectangle();
307 annotBoundingRect.left = annotBoundingRect.left + delta1.x;
308 annotBoundingRect.right = annotBoundingRect.right + delta2.x;
309 annotBoundingRect.top = annotBoundingRect.top + delta1.y;
310 annotBoundingRect.bottom = annotBoundingRect.bottom + delta2.y;
311
312 return annotBoundingRect;
313}
314
315bool AdjustAnnotationCommand::refreshInternalPageReferences(const QVector<Page *> &newPagesVector)
316{
317 // Same reason for not unconditionally updating m_annotation, the annotation pointer can be stored in an add/Remove command
318 auto a = newPagesVector[m_pageNumber]->annotation(m_annotation->uniqueName());
319 if (a) {
320 m_annotation = a;
321 }
322
323 return true;
324}
325
326EditTextCommand::EditTextCommand(const QString &newContents, int newCursorPos, const QString &prevContents, int prevCursorPos, int prevAnchorPos)
327 : m_newContents(newContents)
328 , m_newCursorPos(newCursorPos)
329 , m_prevContents(prevContents)
330 , m_prevCursorPos(prevCursorPos)
331 , m_prevAnchorPos(prevAnchorPos)
332{
333 setText(i18nc("Generic text edit command", "edit text"));
334
335 //// Determine edit type
336 // If There was a selection then edit was not a simple single character backspace, delete, or insert
337 if (m_prevCursorPos != m_prevAnchorPos) {
338 qCDebug(OkularCoreDebug) << "OtherEdit, selection";
339 m_editType = OtherEdit;
340 } else if (newContentsRightOfCursor() == oldContentsRightOfCursor() && newContentsLeftOfCursor() == oldContentsLeftOfCursor().left(oldContentsLeftOfCursor().length() - 1) &&
341 QStringView {oldContentsLeftOfCursor()}.right(1) != QLatin1Char('\n')) {
342 qCDebug(OkularCoreDebug) << "CharBackspace";
343 m_editType = CharBackspace;
344 } else if (newContentsLeftOfCursor() == oldContentsLeftOfCursor() && newContentsRightOfCursor() == oldContentsRightOfCursor().right(oldContentsRightOfCursor().length() - 1) &&
345 QStringView {oldContentsRightOfCursor()}.left(1) != QLatin1Char('\n')) {
346 qCDebug(OkularCoreDebug) << "CharDelete";
347 m_editType = CharDelete;
348 } else if (newContentsRightOfCursor() == oldContentsRightOfCursor() && newContentsLeftOfCursor().left(newContentsLeftOfCursor().length() - 1) == oldContentsLeftOfCursor() &&
349 QStringView {newContentsLeftOfCursor()}.right(1) != QLatin1Char('\n')) {
350 qCDebug(OkularCoreDebug) << "CharInsert";
351 m_editType = CharInsert;
352 } else {
353 qCDebug(OkularCoreDebug) << "OtherEdit";
354 m_editType = OtherEdit;
355 }
356}
357
358bool EditTextCommand::mergeWith(const QUndoCommand *uc)
359{
360 EditTextCommand *euc = (EditTextCommand *)uc;
361
362 // Only attempt merge of euc into this if our new state matches euc's old state and
363 // the editTypes match and are not type OtherEdit
364 if (m_newContents == euc->m_prevContents && m_newCursorPos == euc->m_prevCursorPos && m_editType == euc->m_editType && m_editType != OtherEdit) {
365 m_newContents = euc->m_newContents;
366 m_newCursorPos = euc->m_newCursorPos;
367 return true;
368 }
369 return false;
370}
371
372QString EditTextCommand::oldContentsLeftOfCursor()
373{
374 return m_prevContents.left(m_prevCursorPos);
375}
376
377QString EditTextCommand::oldContentsRightOfCursor()
378{
379 return m_prevContents.right(m_prevContents.length() - m_prevCursorPos);
380}
381
382QString EditTextCommand::newContentsLeftOfCursor()
383{
384 return m_newContents.left(m_newCursorPos);
385}
386
387QString EditTextCommand::newContentsRightOfCursor()
388{
389 return m_newContents.right(m_newContents.length() - m_newCursorPos);
390}
391
392EditAnnotationContentsCommand::EditAnnotationContentsCommand(DocumentPrivate *docPriv, Annotation *annotation, int pageNumber, const QString &newContents, int newCursorPos, const QString &prevContents, int prevCursorPos, int prevAnchorPos)
393 : EditTextCommand(newContents, newCursorPos, prevContents, prevCursorPos, prevAnchorPos)
394 , m_docPriv(docPriv)
395 , m_annotation(annotation)
396 , m_pageNumber(pageNumber)
397{
398 setText(i18nc("Edit an annotation's text contents", "edit annotation contents"));
399}
400
401void EditAnnotationContentsCommand::undo()
402{
403 moveViewportIfBoundingRectNotFullyVisible(m_annotation->boundingRectangle(), m_docPriv, m_pageNumber);
404 m_docPriv->performSetAnnotationContents(m_prevContents, m_annotation, m_pageNumber);
405 Q_EMIT m_docPriv->m_parent->annotationContentsChangedByUndoRedo(m_annotation, m_prevContents, m_prevCursorPos, m_prevAnchorPos);
406}
407
408void EditAnnotationContentsCommand::redo()
409{
410 moveViewportIfBoundingRectNotFullyVisible(m_annotation->boundingRectangle(), m_docPriv, m_pageNumber);
411 m_docPriv->performSetAnnotationContents(m_newContents, m_annotation, m_pageNumber);
412 Q_EMIT m_docPriv->m_parent->annotationContentsChangedByUndoRedo(m_annotation, m_newContents, m_newCursorPos, m_newCursorPos);
413}
414
415int EditAnnotationContentsCommand::id() const
416{
417 return 2;
418}
419
420bool EditAnnotationContentsCommand::mergeWith(const QUndoCommand *uc)
421{
422 EditAnnotationContentsCommand *euc = (EditAnnotationContentsCommand *)uc;
423 // Only attempt merge of euc into this if they modify the same annotation
424 if (m_annotation == euc->m_annotation) {
425 return EditTextCommand::mergeWith(uc);
426 } else {
427 return false;
428 }
429}
430
431bool EditAnnotationContentsCommand::refreshInternalPageReferences(const QVector<Page *> &newPagesVector)
432{
433 auto a = newPagesVector[m_pageNumber]->annotation(m_annotation->uniqueName());
434 if (a) {
435 m_annotation = a;
436 }
437
438 return true;
439}
440
441EditFormTextCommand::EditFormTextCommand(Okular::DocumentPrivate *docPriv, Okular::FormFieldText *form, int pageNumber, const QString &newContents, int newCursorPos, const QString &prevContents, int prevCursorPos, int prevAnchorPos)
442 : EditTextCommand(newContents, newCursorPos, prevContents, prevCursorPos, prevAnchorPos)
443 , m_docPriv(docPriv)
444 , m_form(form)
445 , m_pageNumber(pageNumber)
446{
447 setText(i18nc("Edit an form's text contents", "edit form contents"));
448}
449
450void EditFormTextCommand::undo()
451{
452 moveViewportIfBoundingRectNotFullyVisible(m_form->rect(), m_docPriv, m_pageNumber);
453 m_form->setText(m_prevContents);
454 Q_EMIT m_docPriv->m_parent->formTextChangedByUndoRedo(m_pageNumber, m_form, m_prevContents, m_prevCursorPos, m_prevAnchorPos);
455 m_docPriv->notifyFormChanges(m_pageNumber);
456}
457
458void EditFormTextCommand::redo()
459{
460 moveViewportIfBoundingRectNotFullyVisible(m_form->rect(), m_docPriv, m_pageNumber);
461 m_form->setText(m_newContents);
462 Q_EMIT m_docPriv->m_parent->formTextChangedByUndoRedo(m_pageNumber, m_form, m_newContents, m_newCursorPos, m_newCursorPos);
463 m_docPriv->notifyFormChanges(m_pageNumber);
464}
465
466int EditFormTextCommand::id() const
467{
468 return 3;
469}
470
471bool EditFormTextCommand::mergeWith(const QUndoCommand *uc)
472{
473 EditFormTextCommand *euc = (EditFormTextCommand *)uc;
474 // Only attempt merge of euc into this if they modify the same form
475 if (m_form == euc->m_form) {
476 return EditTextCommand::mergeWith(uc);
477 } else {
478 return false;
479 }
480}
481
482bool EditFormTextCommand::refreshInternalPageReferences(const QVector<Page *> &newPagesVector)
483{
484 m_form = dynamic_cast<FormFieldText *>(Okular::PagePrivate::findEquivalentForm(newPagesVector[m_pageNumber], m_form));
485
486 return m_form;
487}
488
489EditFormListCommand::EditFormListCommand(Okular::DocumentPrivate *docPriv, FormFieldChoice *form, int pageNumber, const QList<int> &newChoices, const QList<int> &prevChoices)
490 : m_docPriv(docPriv)
491 , m_form(form)
492 , m_pageNumber(pageNumber)
493 , m_newChoices(newChoices)
494 , m_prevChoices(prevChoices)
495{
496 setText(i18nc("Edit a list form's choices", "edit list form choices"));
497}
498
499void EditFormListCommand::undo()
500{
501 moveViewportIfBoundingRectNotFullyVisible(m_form->rect(), m_docPriv, m_pageNumber);
502 m_form->setCurrentChoices(m_prevChoices);
503 Q_EMIT m_docPriv->m_parent->formListChangedByUndoRedo(m_pageNumber, m_form, m_prevChoices);
504 m_docPriv->notifyFormChanges(m_pageNumber);
505}
506
507void EditFormListCommand::redo()
508{
509 moveViewportIfBoundingRectNotFullyVisible(m_form->rect(), m_docPriv, m_pageNumber);
510 m_form->setCurrentChoices(m_newChoices);
511 Q_EMIT m_docPriv->m_parent->formListChangedByUndoRedo(m_pageNumber, m_form, m_newChoices);
512 m_docPriv->notifyFormChanges(m_pageNumber);
513}
514
515bool EditFormListCommand::refreshInternalPageReferences(const QVector<Page *> &newPagesVector)
516{
517 m_form = dynamic_cast<FormFieldChoice *>(Okular::PagePrivate::findEquivalentForm(newPagesVector[m_pageNumber], m_form));
518
519 return m_form;
520}
521
522EditFormComboCommand::EditFormComboCommand(Okular::DocumentPrivate *docPriv, FormFieldChoice *form, int pageNumber, const QString &newContents, int newCursorPos, const QString &prevContents, int prevCursorPos, int prevAnchorPos)
523 : EditTextCommand(newContents, newCursorPos, prevContents, prevCursorPos, prevAnchorPos)
524 , m_docPriv(docPriv)
525 , m_form(form)
526 , m_pageNumber(pageNumber)
527 , m_newIndex(-1)
528 , m_prevIndex(-1)
529{
530 setText(i18nc("Edit a combo form's selection", "edit combo form selection"));
531
532 // Determine new and previous choice indices (if any)
533 for (int i = 0; i < m_form->choices().size(); i++) {
534 if (m_form->choices().at(i) == m_prevContents) {
535 m_prevIndex = i;
536 }
537
538 if (m_form->choices().at(i) == m_newContents) {
539 m_newIndex = i;
540 }
541 }
542}
543
544void EditFormComboCommand::undo()
545{
546 if (m_prevIndex != -1) {
547 m_form->setCurrentChoices(QList<int>() << m_prevIndex);
548 } else {
549 m_form->setEditChoice(m_prevContents);
550 }
551 moveViewportIfBoundingRectNotFullyVisible(m_form->rect(), m_docPriv, m_pageNumber);
552 Q_EMIT m_docPriv->m_parent->formComboChangedByUndoRedo(m_pageNumber, m_form, m_prevContents, m_prevCursorPos, m_prevAnchorPos);
553 m_docPriv->notifyFormChanges(m_pageNumber);
554}
555
556void EditFormComboCommand::redo()
557{
558 if (m_newIndex != -1) {
559 m_form->setCurrentChoices(QList<int>() << m_newIndex);
560 } else {
561 m_form->setEditChoice(m_newContents);
562 }
563 moveViewportIfBoundingRectNotFullyVisible(m_form->rect(), m_docPriv, m_pageNumber);
564 Q_EMIT m_docPriv->m_parent->formComboChangedByUndoRedo(m_pageNumber, m_form, m_newContents, m_newCursorPos, m_newCursorPos);
565 m_docPriv->notifyFormChanges(m_pageNumber);
566}
567
568int EditFormComboCommand::id() const
569{
570 return 4;
571}
572
573bool EditFormComboCommand::mergeWith(const QUndoCommand *uc)
574{
575 EditFormComboCommand *euc = (EditFormComboCommand *)uc;
576 // Only attempt merge of euc into this if they modify the same form
577 if (m_form == euc->m_form) {
578 bool shouldMerge = EditTextCommand::mergeWith(uc);
579 if (shouldMerge) {
580 m_newIndex = euc->m_newIndex;
581 }
582 return shouldMerge;
583 } else {
584 return false;
585 }
586}
587
588bool EditFormComboCommand::refreshInternalPageReferences(const QVector<Page *> &newPagesVector)
589{
590 m_form = dynamic_cast<FormFieldChoice *>(Okular::PagePrivate::findEquivalentForm(newPagesVector[m_pageNumber], m_form));
591
592 return m_form;
593}
594
595EditFormButtonsCommand::EditFormButtonsCommand(Okular::DocumentPrivate *docPriv, int pageNumber, const QList<FormFieldButton *> &formButtons, const QList<bool> &newButtonStates)
596 : m_docPriv(docPriv)
597 , m_pageNumber(pageNumber)
598 , m_formButtons(formButtons)
599 , m_newButtonStates(newButtonStates)
600 , m_prevButtonStates(QList<bool>())
601{
602 setText(i18nc("Edit the state of a group of form buttons", "edit form button states"));
603 for (const FormFieldButton *formButton : std::as_const(m_formButtons)) {
604 m_prevButtonStates.append(formButton->state());
605 m_pageNumbers.append(formButton->page()->number());
606 }
607}
608
609void EditFormButtonsCommand::undo()
610{
611 clearFormButtonStates();
612 QSet<int> extraPages;
613 for (int i = 0; i < m_formButtons.size(); i++) {
614 bool checked = m_prevButtonStates.at(i);
615 if (checked) {
616 m_formButtons.at(i)->setState(checked);
617 }
618 if (m_pageNumbers.at(i) != m_pageNumber) {
619 extraPages << m_pageNumbers.at(i);
620 }
621 }
622
623 Okular::NormalizedRect boundingRect = buildBoundingRectangleForButtons(m_formButtons);
624 moveViewportIfBoundingRectNotFullyVisible(boundingRect, m_docPriv, m_pageNumber);
625 Q_EMIT m_docPriv->m_parent->formButtonsChangedByUndoRedo(m_pageNumber, m_formButtons);
626 m_docPriv->notifyFormChanges(m_pageNumber);
627 for (auto page : std::as_const(extraPages)) {
628 m_docPriv->notifyFormChanges(page);
629 }
630}
631
632void EditFormButtonsCommand::redo()
633{
634 clearFormButtonStates();
635 QSet<int> extraPages;
636 for (int i = 0; i < m_formButtons.size(); i++) {
637 bool checked = m_newButtonStates.at(i);
638 if (checked) {
639 m_formButtons.at(i)->setState(checked);
640 }
641 if (m_pageNumbers.at(i) != m_pageNumber) {
642 extraPages << m_pageNumbers.at(i);
643 }
644 }
645
646 Okular::NormalizedRect boundingRect = buildBoundingRectangleForButtons(m_formButtons);
647 moveViewportIfBoundingRectNotFullyVisible(boundingRect, m_docPriv, m_pageNumber);
648 Q_EMIT m_docPriv->m_parent->formButtonsChangedByUndoRedo(m_pageNumber, m_formButtons);
649 m_docPriv->notifyFormChanges(m_pageNumber);
650 for (auto page : std::as_const(extraPages)) {
651 m_docPriv->notifyFormChanges(page);
652 }
653}
654
655bool EditFormButtonsCommand::refreshInternalPageReferences(const QVector<Okular::Page *> &newPagesVector)
656{
657 const QList<FormFieldButton *> oldFormButtons = m_formButtons;
658 m_formButtons.clear();
659 for (int i = 0; i < oldFormButtons.size(); i++) {
660 FormFieldButton *button = dynamic_cast<FormFieldButton *>(Okular::PagePrivate::findEquivalentForm(newPagesVector[m_pageNumbers[i]], oldFormButtons[i]));
661 if (!button) {
662 return false;
663 }
664 m_formButtons << button;
665 }
666
667 return true;
668}
669
670void EditFormButtonsCommand::clearFormButtonStates()
671{
672 for (FormFieldButton *formButton : std::as_const(m_formButtons)) {
673 formButton->setState(false);
674 }
675}
676
677}
Annotation struct holds properties shared by all annotations.
Definition annotations.h:96
Interface of a text form field.
Definition form.h:261
NormalizedPoint is a helper class which stores the coordinates of a normalized point.
Definition area.h:117
double x
The normalized x coordinate.
Definition area.h:166
double y
The normalized y coordinate.
Definition area.h:171
A NormalizedRect is a rectangle which can be defined by two NormalizedPoints.
Definition area.h:189
double bottom
The normalized bottom coordinate.
Definition area.h:435
double right
The normalized right coordinate.
Definition area.h:430
double left
The normalized left coordinate.
Definition area.h:420
double top
The normalized top coordinate.
Definition area.h:425
void transform(const QTransform &matrix)
Transforms the normalized rectangle with the operations defined by matrix.
Definition area.cpp:253
QString i18nc(const char *context, const char *text, const TYPE &arg...)
global.h
Definition action.h:17
void clear()
qsizetype size() const const
QString left(qsizetype n) const const
QString right(qsizetype n) const const
QStringView left(qsizetype length) const const
QStringView right(qsizetype length) const const
QTextStream & left(QTextStream &stream)
QTextStream & right(QTextStream &stream)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Tue Mar 26 2024 11:17:35 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.