Okular

documentcommands.cpp
1 /*
2  SPDX-FileCopyrightText: 2013 Jon Mease <[email protected]>
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 <[email protected]>
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 
22 namespace Okular
23 {
24 void 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 
38 Okular::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 
56 AddAnnotationCommand::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 
65 AddAnnotationCommand::~AddAnnotationCommand()
66 {
67  if (!m_done) {
68  delete m_annotation;
69  }
70 }
71 
72 void 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 
79 void 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 
86 bool 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 
102 RemoveAnnotationCommand::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 
111 RemoveAnnotationCommand::~RemoveAnnotationCommand()
112 {
113  if (m_done) {
114  delete m_annotation;
115  }
116 }
117 
118 void 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 
125 void 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 
132 bool 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 
148 ModifyAnnotationPropertiesCommand::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 
158 void 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 
165 void 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 
172 bool 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 
183 TranslateAnnotationCommand::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 
193 void 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 
200 void 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 
207 int TranslateAnnotationCommand::id() const
208 {
209  return 1;
210 }
211 
212 bool 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 
228 Okular::NormalizedPoint TranslateAnnotationCommand::minusDelta()
229 {
230  return Okular::NormalizedPoint(-m_delta.x, -m_delta.y);
231 }
232 
233 Okular::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 
244 bool 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 
255 AdjustAnnotationCommand::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 
266 void 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 
275 void 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 
282 int AdjustAnnotationCommand::id() const
283 {
284  return 5;
285 }
286 
287 bool 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 
304 Okular::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 
315 bool 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 
326 EditTextCommand::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) && oldContentsLeftOfCursor().rightRef(1) != QLatin1Char('\n')) {
341  qCDebug(OkularCoreDebug) << "CharBackspace";
342  m_editType = CharBackspace;
343  } else if (newContentsLeftOfCursor() == oldContentsLeftOfCursor() && newContentsRightOfCursor() == oldContentsRightOfCursor().right(oldContentsRightOfCursor().length() - 1) &&
344  oldContentsRightOfCursor().leftRef(1) != QLatin1Char('\n')) {
345  qCDebug(OkularCoreDebug) << "CharDelete";
346  m_editType = CharDelete;
347  } else if (newContentsRightOfCursor() == oldContentsRightOfCursor() && newContentsLeftOfCursor().left(newContentsLeftOfCursor().length() - 1) == oldContentsLeftOfCursor() && newContentsLeftOfCursor().rightRef(1) != QLatin1Char('\n')) {
348  qCDebug(OkularCoreDebug) << "CharInsert";
349  m_editType = CharInsert;
350  } else {
351  qCDebug(OkularCoreDebug) << "OtherEdit";
352  m_editType = OtherEdit;
353  }
354 }
355 
356 bool EditTextCommand::mergeWith(const QUndoCommand *uc)
357 {
358  EditTextCommand *euc = (EditTextCommand *)uc;
359 
360  // Only attempt merge of euc into this if our new state matches euc's old state and
361  // the editTypes match and are not type OtherEdit
362  if (m_newContents == euc->m_prevContents && m_newCursorPos == euc->m_prevCursorPos && m_editType == euc->m_editType && m_editType != OtherEdit) {
363  m_newContents = euc->m_newContents;
364  m_newCursorPos = euc->m_newCursorPos;
365  return true;
366  }
367  return false;
368 }
369 
370 QString EditTextCommand::oldContentsLeftOfCursor()
371 {
372  return m_prevContents.left(m_prevCursorPos);
373 }
374 
375 QString EditTextCommand::oldContentsRightOfCursor()
376 {
377  return m_prevContents.right(m_prevContents.length() - m_prevCursorPos);
378 }
379 
380 QString EditTextCommand::newContentsLeftOfCursor()
381 {
382  return m_newContents.left(m_newCursorPos);
383 }
384 
385 QString EditTextCommand::newContentsRightOfCursor()
386 {
387  return m_newContents.right(m_newContents.length() - m_newCursorPos);
388 }
389 
390 EditAnnotationContentsCommand::EditAnnotationContentsCommand(DocumentPrivate *docPriv, Annotation *annotation, int pageNumber, const QString &newContents, int newCursorPos, const QString &prevContents, int prevCursorPos, int prevAnchorPos)
391  : EditTextCommand(newContents, newCursorPos, prevContents, prevCursorPos, prevAnchorPos)
392  , m_docPriv(docPriv)
393  , m_annotation(annotation)
394  , m_pageNumber(pageNumber)
395 {
396  setText(i18nc("Edit an annotation's text contents", "edit annotation contents"));
397 }
398 
399 void EditAnnotationContentsCommand::undo()
400 {
401  moveViewportIfBoundingRectNotFullyVisible(m_annotation->boundingRectangle(), m_docPriv, m_pageNumber);
402  m_docPriv->performSetAnnotationContents(m_prevContents, m_annotation, m_pageNumber);
403  Q_EMIT m_docPriv->m_parent->annotationContentsChangedByUndoRedo(m_annotation, m_prevContents, m_prevCursorPos, m_prevAnchorPos);
404 }
405 
406 void EditAnnotationContentsCommand::redo()
407 {
408  moveViewportIfBoundingRectNotFullyVisible(m_annotation->boundingRectangle(), m_docPriv, m_pageNumber);
409  m_docPriv->performSetAnnotationContents(m_newContents, m_annotation, m_pageNumber);
410  Q_EMIT m_docPriv->m_parent->annotationContentsChangedByUndoRedo(m_annotation, m_newContents, m_newCursorPos, m_newCursorPos);
411 }
412 
413 int EditAnnotationContentsCommand::id() const
414 {
415  return 2;
416 }
417 
418 bool EditAnnotationContentsCommand::mergeWith(const QUndoCommand *uc)
419 {
420  EditAnnotationContentsCommand *euc = (EditAnnotationContentsCommand *)uc;
421  // Only attempt merge of euc into this if they modify the same annotation
422  if (m_annotation == euc->m_annotation) {
423  return EditTextCommand::mergeWith(uc);
424  } else {
425  return false;
426  }
427 }
428 
429 bool EditAnnotationContentsCommand::refreshInternalPageReferences(const QVector<Page *> &newPagesVector)
430 {
431  auto a = newPagesVector[m_pageNumber]->annotation(m_annotation->uniqueName());
432  if (a) {
433  m_annotation = a;
434  }
435 
436  return true;
437 }
438 
439 EditFormTextCommand::EditFormTextCommand(Okular::DocumentPrivate *docPriv, Okular::FormFieldText *form, int pageNumber, const QString &newContents, int newCursorPos, const QString &prevContents, int prevCursorPos, int prevAnchorPos)
440  : EditTextCommand(newContents, newCursorPos, prevContents, prevCursorPos, prevAnchorPos)
441  , m_docPriv(docPriv)
442  , m_form(form)
443  , m_pageNumber(pageNumber)
444 {
445  setText(i18nc("Edit an form's text contents", "edit form contents"));
446 }
447 
448 void EditFormTextCommand::undo()
449 {
450  moveViewportIfBoundingRectNotFullyVisible(m_form->rect(), m_docPriv, m_pageNumber);
451  m_form->setText(m_prevContents);
452  Q_EMIT m_docPriv->m_parent->formTextChangedByUndoRedo(m_pageNumber, m_form, m_prevContents, m_prevCursorPos, m_prevAnchorPos);
453  m_docPriv->notifyFormChanges(m_pageNumber);
454 }
455 
456 void EditFormTextCommand::redo()
457 {
458  moveViewportIfBoundingRectNotFullyVisible(m_form->rect(), m_docPriv, m_pageNumber);
459  m_form->setText(m_newContents);
460  Q_EMIT m_docPriv->m_parent->formTextChangedByUndoRedo(m_pageNumber, m_form, m_newContents, m_newCursorPos, m_newCursorPos);
461  m_docPriv->notifyFormChanges(m_pageNumber);
462 }
463 
464 int EditFormTextCommand::id() const
465 {
466  return 3;
467 }
468 
469 bool EditFormTextCommand::mergeWith(const QUndoCommand *uc)
470 {
471  EditFormTextCommand *euc = (EditFormTextCommand *)uc;
472  // Only attempt merge of euc into this if they modify the same form
473  if (m_form == euc->m_form) {
474  return EditTextCommand::mergeWith(uc);
475  } else {
476  return false;
477  }
478 }
479 
480 bool EditFormTextCommand::refreshInternalPageReferences(const QVector<Page *> &newPagesVector)
481 {
482  m_form = dynamic_cast<FormFieldText *>(Okular::PagePrivate::findEquivalentForm(newPagesVector[m_pageNumber], m_form));
483 
484  return m_form;
485 }
486 
487 EditFormListCommand::EditFormListCommand(Okular::DocumentPrivate *docPriv, FormFieldChoice *form, int pageNumber, const QList<int> &newChoices, const QList<int> &prevChoices)
488  : m_docPriv(docPriv)
489  , m_form(form)
490  , m_pageNumber(pageNumber)
491  , m_newChoices(newChoices)
492  , m_prevChoices(prevChoices)
493 {
494  setText(i18nc("Edit a list form's choices", "edit list form choices"));
495 }
496 
497 void EditFormListCommand::undo()
498 {
499  moveViewportIfBoundingRectNotFullyVisible(m_form->rect(), m_docPriv, m_pageNumber);
500  m_form->setCurrentChoices(m_prevChoices);
501  Q_EMIT m_docPriv->m_parent->formListChangedByUndoRedo(m_pageNumber, m_form, m_prevChoices);
502  m_docPriv->notifyFormChanges(m_pageNumber);
503 }
504 
505 void EditFormListCommand::redo()
506 {
507  moveViewportIfBoundingRectNotFullyVisible(m_form->rect(), m_docPriv, m_pageNumber);
508  m_form->setCurrentChoices(m_newChoices);
509  Q_EMIT m_docPriv->m_parent->formListChangedByUndoRedo(m_pageNumber, m_form, m_newChoices);
510  m_docPriv->notifyFormChanges(m_pageNumber);
511 }
512 
513 bool EditFormListCommand::refreshInternalPageReferences(const QVector<Page *> &newPagesVector)
514 {
515  m_form = dynamic_cast<FormFieldChoice *>(Okular::PagePrivate::findEquivalentForm(newPagesVector[m_pageNumber], m_form));
516 
517  return m_form;
518 }
519 
520 EditFormComboCommand::EditFormComboCommand(Okular::DocumentPrivate *docPriv, FormFieldChoice *form, int pageNumber, const QString &newContents, int newCursorPos, const QString &prevContents, int prevCursorPos, int prevAnchorPos)
521  : EditTextCommand(newContents, newCursorPos, prevContents, prevCursorPos, prevAnchorPos)
522  , m_docPriv(docPriv)
523  , m_form(form)
524  , m_pageNumber(pageNumber)
525  , m_newIndex(-1)
526  , m_prevIndex(-1)
527 {
528  setText(i18nc("Edit a combo form's selection", "edit combo form selection"));
529 
530  // Determine new and previous choice indices (if any)
531  for (int i = 0; i < m_form->choices().size(); i++) {
532  if (m_form->choices().at(i) == m_prevContents) {
533  m_prevIndex = i;
534  }
535 
536  if (m_form->choices().at(i) == m_newContents) {
537  m_newIndex = i;
538  }
539  }
540 }
541 
542 void EditFormComboCommand::undo()
543 {
544  if (m_prevIndex != -1) {
545  m_form->setCurrentChoices(QList<int>() << m_prevIndex);
546  } else {
547  m_form->setEditChoice(m_prevContents);
548  }
549  moveViewportIfBoundingRectNotFullyVisible(m_form->rect(), m_docPriv, m_pageNumber);
550  Q_EMIT m_docPriv->m_parent->formComboChangedByUndoRedo(m_pageNumber, m_form, m_prevContents, m_prevCursorPos, m_prevAnchorPos);
551  m_docPriv->notifyFormChanges(m_pageNumber);
552 }
553 
554 void EditFormComboCommand::redo()
555 {
556  if (m_newIndex != -1) {
557  m_form->setCurrentChoices(QList<int>() << m_newIndex);
558  } else {
559  m_form->setEditChoice(m_newContents);
560  }
561  moveViewportIfBoundingRectNotFullyVisible(m_form->rect(), m_docPriv, m_pageNumber);
562  Q_EMIT m_docPriv->m_parent->formComboChangedByUndoRedo(m_pageNumber, m_form, m_newContents, m_newCursorPos, m_newCursorPos);
563  m_docPriv->notifyFormChanges(m_pageNumber);
564 }
565 
566 int EditFormComboCommand::id() const
567 {
568  return 4;
569 }
570 
571 bool EditFormComboCommand::mergeWith(const QUndoCommand *uc)
572 {
573  EditFormComboCommand *euc = (EditFormComboCommand *)uc;
574  // Only attempt merge of euc into this if they modify the same form
575  if (m_form == euc->m_form) {
576  bool shouldMerge = EditTextCommand::mergeWith(uc);
577  if (shouldMerge) {
578  m_newIndex = euc->m_newIndex;
579  }
580  return shouldMerge;
581  } else {
582  return false;
583  }
584 }
585 
586 bool EditFormComboCommand::refreshInternalPageReferences(const QVector<Page *> &newPagesVector)
587 {
588  m_form = dynamic_cast<FormFieldChoice *>(Okular::PagePrivate::findEquivalentForm(newPagesVector[m_pageNumber], m_form));
589 
590  return m_form;
591 }
592 
593 EditFormButtonsCommand::EditFormButtonsCommand(Okular::DocumentPrivate *docPriv, int pageNumber, const QList<FormFieldButton *> &formButtons, const QList<bool> &newButtonStates)
594  : m_docPriv(docPriv)
595  , m_pageNumber(pageNumber)
596  , m_formButtons(formButtons)
597  , m_newButtonStates(newButtonStates)
598  , m_prevButtonStates(QList<bool>())
599 {
600  setText(i18nc("Edit the state of a group of form buttons", "edit form button states"));
601  for (const FormFieldButton *formButton : qAsConst(m_formButtons)) {
602  m_prevButtonStates.append(formButton->state());
603  }
604 }
605 
606 void EditFormButtonsCommand::undo()
607 {
608  clearFormButtonStates();
609  for (int i = 0; i < m_formButtons.size(); i++) {
610  bool checked = m_prevButtonStates.at(i);
611  if (checked) {
612  m_formButtons.at(i)->setState(checked);
613  }
614  }
615 
616  Okular::NormalizedRect boundingRect = buildBoundingRectangleForButtons(m_formButtons);
617  moveViewportIfBoundingRectNotFullyVisible(boundingRect, m_docPriv, m_pageNumber);
618  Q_EMIT m_docPriv->m_parent->formButtonsChangedByUndoRedo(m_pageNumber, m_formButtons);
619  m_docPriv->notifyFormChanges(m_pageNumber);
620 }
621 
622 void EditFormButtonsCommand::redo()
623 {
624  clearFormButtonStates();
625  for (int i = 0; i < m_formButtons.size(); i++) {
626  bool checked = m_newButtonStates.at(i);
627  if (checked) {
628  m_formButtons.at(i)->setState(checked);
629  }
630  }
631 
632  Okular::NormalizedRect boundingRect = buildBoundingRectangleForButtons(m_formButtons);
633  moveViewportIfBoundingRectNotFullyVisible(boundingRect, m_docPriv, m_pageNumber);
634  Q_EMIT m_docPriv->m_parent->formButtonsChangedByUndoRedo(m_pageNumber, m_formButtons);
635  m_docPriv->notifyFormChanges(m_pageNumber);
636 }
637 
638 bool EditFormButtonsCommand::refreshInternalPageReferences(const QVector<Okular::Page *> &newPagesVector)
639 {
640  const QList<FormFieldButton *> oldFormButtons = m_formButtons;
641  m_formButtons.clear();
642  for (FormFieldButton *oldFormButton : oldFormButtons) {
643  FormFieldButton *button = dynamic_cast<FormFieldButton *>(Okular::PagePrivate::findEquivalentForm(newPagesVector[m_pageNumber], oldFormButton));
644  if (!button) {
645  return false;
646  }
647  m_formButtons << button;
648  }
649 
650  return true;
651 }
652 
653 void EditFormButtonsCommand::clearFormButtonStates()
654 {
655  for (FormFieldButton *formButton : qAsConst(m_formButtons)) {
656  formButton->setState(false);
657  }
658 }
659 
660 }
QTextStream & right(QTextStream &stream)
double y
The normalized y coordinate.
Definition: area.h:171
The documentation to the global Okular namespace.
Definition: action.h:16
Annotation struct holds properties shared by all annotations.
Definition: annotations.h:95
QTextStream & left(QTextStream &stream)
NormalizedPoint is a helper class which stores the coordinates of a normalized point.
Definition: area.h:116
Interface of a text form field.
Definition: form.h:260
A NormalizedRect is a rectangle which can be defined by two NormalizedPoints.
Definition: area.h:188
double left
The normalized left coordinate.
Definition: area.h:420
double x
The normalized x coordinate.
Definition: area.h:166
double right
The normalized right coordinate.
Definition: area.h:430
void transform(const QTransform &matrix)
Transforms the normalized rectangle with the operations defined by matrix.
Definition: area.cpp:253
QString left(int n) const const
QString right(int n) const const
void clear()
QString i18nc(const char *context, const char *text, const TYPE &arg...)
double top
The normalized top coordinate.
Definition: area.h:425
double bottom
The normalized bottom coordinate.
Definition: area.h:435
Rotation
A rotation.
Definition: global.h:45
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Thu Mar 23 2023 04:04:24 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.