1 /*
2 For general Scribus (>=1.3.2) copyright and licensing information please refer
3 to the COPYING file provided with the program. Following this notice may exist
4 a copyright and/or license notice that predates the release of Scribus 1.3.2
5 for which a new license (GPL+exception) is in place.
6 */
7 /***************************************************************************
8                           page.cpp  -  description
9                              -------------------
10     begin                : Sat Apr 7 2001
11     copyright            : (C) 2001 by Franz Schmid
12     email                : Franz.Schmid@altmuehlnet.de
13  ***************************************************************************/
14 
15 /***************************************************************************
16  *                                                                         *
17  *   This program is free software; you can redistribute it and/or modify  *
18  *   it under the terms of the GNU General Public License as published by  *
19  *   the Free Software Foundation; either version 2 of the License, or     *
20  *   (at your option) any later version.                                   *
21  *                                                                         *
22  ***************************************************************************/
23 
24 #include <QDebug>
25 #include <QPixmap>
26 
27 #include "appmodehelper.h"
28 #include "scpage.h"
29 #include "scribus.h"
30 #include "scribusdoc.h"
31 #include "scribusview.h"
32 #include "selection.h"
33 #include "undomanager.h"
34 #include "undostate.h"
35 
36 #include "ui/guidemanager.h"
37 #include "ui/nodeeditpalette.h"
38 
ScPage(const double x,const double y,const double b,const double h)39 ScPage::ScPage(const double x, const double y, const double b, const double h) :
40 	UndoObject(QObject::tr("Page")),
41 	SingleObservable<ScPage>(nullptr),
42 	Margins(40,40,40,40),
43 	initialMargins(40,40,40,40),
44 	undoManager(UndoManager::instance()),
45 	m_xOffset(x),
46 	m_yOffset(y),
47 	m_width(b),
48 	m_height(h),
49 	m_initialWidth(b),
50 	m_initialHeight(h)
51 {
52 	guides.setPage(this);
53 }
54 
~ScPage()55 ScPage::~ScPage()
56 {
57 	// Clean up any modified template items (unused)
58 //	for (PageItem *currItem = FromMaster.first(); currItem; currItem = FromMaster.next())
59 //	{
60 //		if (currItem->ChangedMasterItem)
61 //		{
62 //			FromMaster.remove(currItem);
63 //			delete currItem;
64 //		}
65 //	}
66 	FromMaster.clear();
67 }
68 
bleedRect() const69 QRectF ScPage::bleedRect() const
70 {
71 	QRectF pageRect(m_xOffset, m_yOffset, m_width, m_height);
72 	if (m_Doc)
73 	{
74 		MarginStruct pageBleeds;
75 		m_Doc->getBleeds(this, pageBleeds);
76 		double totalWidth = m_width + pageBleeds.left() + pageBleeds.right();
77 		double totalHeight = m_height + pageBleeds.bottom() + pageBleeds.top();
78 		pageRect = QRectF(m_xOffset - pageBleeds.left(), m_yOffset - pageBleeds.top(), totalWidth, totalHeight);
79 	}
80 	return pageRect;
81 }
82 
trimRect() const83 QRectF ScPage::trimRect() const
84 {
85 	QRectF pageRect(m_xOffset, m_yOffset, m_width, m_height);
86 	return pageRect;
87 }
88 
setDocument(ScribusDoc * doc)89 void ScPage::setDocument(ScribusDoc *doc)
90 {
91 	m_Doc=doc;
92 	setMassObservable(doc? doc->pagesChanged() : nullptr);
93 }
94 
setPageNr(int pageNr)95 void ScPage::setPageNr(int pageNr)
96 {
97 	m_pageNr = pageNr;
98 	if (m_pageName.isEmpty())
99 		setUName(QString(QObject::tr("Page") + " %1").arg(m_Doc->FirstPnum + m_pageNr));
100 	else
101 		setUName(m_pageName);
102 }
103 
setPageName(const QString & newName)104 void ScPage::setPageName(const QString& newName)
105 {
106 	m_pageName = newName;
107 	if (!newName.isEmpty())
108 		setUName(QObject::tr("Master Page ") + newName);
109 }
110 
resetPageName()111 void ScPage::resetPageName()
112 {
113 	m_pageName.clear();
114 }
115 
setMasterPageName(const QString & newName)116 void ScPage::setMasterPageName(const QString& newName)
117 {
118 	m_masterPageName = newName;
119 }
120 
setMasterPageNameNormal()121 void ScPage::setMasterPageNameNormal()
122 {
123 	m_masterPageName = CommonStrings::trMasterPageNormal;
124 }
125 
clearMasterPageName()126 void ScPage::clearMasterPageName()
127 {
128 	m_masterPageName.clear();
129 }
130 
setSize(const QString & newSize)131 void ScPage::setSize(const QString& newSize)
132 {
133 	m_pageSize = newSize;
134 }
135 
restore(UndoState * state,bool isUndo)136 void ScPage::restore(UndoState* state, bool isUndo)
137 {
138 	auto* ss = dynamic_cast<SimpleState*>(state);
139 	if (!ss)
140 		return;
141 	if (ss->contains("ADD_V"))
142 	{
143 		double position = ss->getDouble("ADD_V");
144 		if (isUndo)
145 			guides.deleteVertical(position, GuideManagerCore::Standard);//removeXGuide(position);
146 		else
147 			guides.addVertical(position, GuideManagerCore::Standard);//addXGuide(position);
148 		m_Doc->scMW()->guidePalette->setupGui();
149 	}
150 	else if (ss->contains("ADD_H"))
151 	{
152 		double position = ss->getDouble("ADD_H");
153 		if (isUndo)
154 			guides.deleteHorizontal(position, GuideManagerCore::Standard);//removeYGuide(position);
155 		else
156 			guides.addHorizontal(position, GuideManagerCore::Standard);//addYGuide(position);
157 		m_Doc->scMW()->guidePalette->setupGui();
158 	}
159 	else if (ss->contains("REMOVE_V"))
160 	{
161 		double position = ss->getDouble("REMOVE_V");
162 		if (isUndo)
163 			guides.addVertical(position, GuideManagerCore::Standard);//addXGuide(position);
164 		else
165 			guides.deleteVertical(position, GuideManagerCore::Standard);//removeXGuide(position);
166 		m_Doc->scMW()->guidePalette->setupGui();
167 	}
168 	else if (ss->contains("REMOVE_H"))
169 	{
170 		double position = ss->getDouble("REMOVE_H");
171 		if (isUndo)
172 			guides.addHorizontal(position, GuideManagerCore::Standard);//addYGuide(position);
173 		else
174 			guides.deleteHorizontal(position, GuideManagerCore::Standard);//removeYGuide(position);
175 		m_Doc->scMW()->guidePalette->setupGui();
176 	}
177 	else if (ss->contains("MOVE_H_FROM"))
178 	{
179 		double from = ss->getDouble("MOVE_H_FROM");
180 		double to   = ss->getDouble("MOVE_H_TO");
181 		if (isUndo)
182 		{
183 			guides.deleteHorizontal(to, GuideManagerCore::Standard);//removeYGuide(position);
184 			guides.addHorizontal(from, GuideManagerCore::Standard);//addYGuide(position);
185 		}
186 		else
187 		{
188 			guides.deleteHorizontal(from, GuideManagerCore::Standard);//removeYGuide(position);
189 			guides.addHorizontal(to, GuideManagerCore::Standard);//addYGuide(position);
190 		}
191 		m_Doc->scMW()->guidePalette->setupGui();
192 	}
193 	else if (ss->contains("MOVE_V_FROM"))
194 	{
195 		double from = ss->getDouble("MOVE_V_FROM");
196 		double to   = ss->getDouble("MOVE_V_TO");
197 		if (isUndo)
198 		{
199 			guides.deleteVertical(to, GuideManagerCore::Standard);//removeXGuide(position);
200 			guides.addVertical(from, GuideManagerCore::Standard);//removeXGuide(position);
201 		}
202 		else
203 		{
204 			guides.deleteVertical(from, GuideManagerCore::Standard);//removeXGuide(position);
205 			guides.addVertical(to, GuideManagerCore::Standard);//removeXGuide(position);
206 		}
207 		m_Doc->scMW()->guidePalette->setupGui();
208 	}
209 	// automatic guides
210 	else if (ss->contains("REMOVE_HA_GAP"))
211 	{
212 		if (isUndo)
213 		{
214 			guides.setHorizontalAutoCount(ss->getInt("REMOVE_HA_COUNT"));
215 			guides.setHorizontalAutoGap(ss->getDouble("REMOVE_HA_GAP"));
216 			guides.setHorizontalAutoRefer(ss->getInt("REMOVE_HA_REFER"));
217 		}
218 		else
219 		{
220 			guides.setHorizontalAutoCount(0);
221 			guides.setHorizontalAutoGap(0.0);
222 			guides.setHorizontalAutoRefer(0);
223 		}
224 		m_Doc->scMW()->guidePalette->setupGui();
225 	}
226 	else if (ss->contains("REMOVE_VA_GAP"))
227 	{
228 		if (isUndo)
229 		{
230 			guides.setVerticalAutoCount(ss->getInt("REMOVE_VA_COUNT"));
231 			guides.setVerticalAutoGap(ss->getDouble("REMOVE_VA_GAP"));
232 			guides.setVerticalAutoRefer(ss->getInt("REMOVE_VA_REFER"));
233 		}
234 		else
235 		{
236 			guides.setVerticalAutoCount(0);
237 			guides.setVerticalAutoGap(0.0);
238 			guides.setVerticalAutoRefer(0);
239 		}
240 		m_Doc->scMW()->guidePalette->setupGui();
241 	}
242 	else if (ss->contains("CREATE_ITEM"))
243 		restorePageItemCreation(dynamic_cast<ScItemState<PageItem*>*>(ss), isUndo);
244 	else if (ss->contains("DELETE_ITEM"))
245 		restorePageItemDeletion(dynamic_cast<ScItemState< QList<PageItem*> >*>(ss), isUndo);
246 	else if (ss->contains("CONVERT_ITEM"))
247 		restorePageItemConversion(dynamic_cast<ScItemState<QPair<PageItem*, PageItem*> >*>(ss), isUndo);
248 	else if (ss->contains("CONVERT_ITEM_TO_SYMBOL"))
249 		restorePageItemConversionToSymbol(dynamic_cast<ScItemState<QPair<PageItem*, PageItem*> >*>(ss), isUndo);
250 	else if (ss->contains("PAGE_ATTRS"))
251 		restorePageAttributes(ss, isUndo);
252 }
253 
restorePageAttributes(SimpleState * state,bool isUndo)254 void ScPage::restorePageAttributes(SimpleState *state, bool isUndo)
255 {
256 	int left_old = state->getInt("LEFT_OLD");
257 	QString name_old = state->get("NAME_OLD");
258 	int orientation_old = state->getInt("ORIENTATION_OLD");
259 	QString size_old =state->get("SIZE_OLD");
260 	double width_old = state->getDouble("WIDTH_OLD");
261 	double height_old = state->getDouble("HEIGHT_OLD");
262 	double init_height_old = state->getDouble("INIT_HEIGHT_OLD");
263 	double init_width_old = state->getDouble("INIT_WIDTH_OLD");
264 	double init_margin_top_old = state->getDouble("INIT_MARGINTOP_OLD");
265 	double init_margin_bottom_old = state->getDouble("INIT_MARGINBOTTOM_OLD");
266 	double init_margin_right_old = state->getDouble("INIT_MARGINRIGHT_OLD");
267 	double init_margin_left_old = state->getDouble("INIT_MARGINLEFT_OLD");
268 	double margin_top_old = state->getDouble("MARGINTOP_OLD");
269 	double margin_bottom_old = state->getDouble("MARGINBOTTOM_OLD");
270 	int margin_preset_old = state->getInt("MARGINPRESET_OLD");
271 	int left = state->getInt("LEFT");
272 	QString name = state->get("NAME");
273 	int orientation = state->getInt("ORIENTATION");
274 	QString size =state->get("SIZE");
275 	double width = state->getDouble("WIDTH");
276 	double height = state->getDouble("HEIGHT");
277 	double init_height = state->getDouble("INIT_HEIGHT");
278 	double init_width = state->getDouble("INIT_WIDTH");
279 	double init_margin_top = state->getDouble("INIT_MARGINTOP");
280 	double init_margin_bottom = state->getDouble("INIT_MARGINBOTTOM");
281 	double init_margin_right = state->getDouble("INIT_MARGINRIGHT");
282 	double init_margin_left = state->getDouble("INIT_MARGINLEFT");
283 	double margin_top = state->getDouble("MARGINTOP");
284 	double margin_bottom = state->getDouble("MARGINBOTTOM");
285 	int margin_preset = state->getInt("MARGINPRESET");
286 	double horizontal_autogap_old = state->getDouble("HORIZONTAL_AUTOGAP");
287 	double vertical_autogap_old = state->getDouble("VERTICAL_AUTOGAP");
288 	double horizontal_autocount_old = state->getDouble("HORIZONTAL_AUTOCOUNT");
289 	double vertical_autocount_old = state->getDouble("VERTICAL_AUTOCOUNT");
290 	double horizontal_autorefer_old = state->getDouble("HORIZONTAL_AUTOREFER");
291 	double vertical_autorefer_old = state->getDouble("VERTICAL_AUTOREFER");
292 	double horizontal_autogap = state->getDouble("HORIZONTAL_AUTOGAP");
293 	double vertical_autogap = state->getDouble("VERTICAL_AUTOGAP");
294 	double horizontal_autocount = state->getDouble("HORIZONTAL_AUTOCOUNT");
295 	double vertical_autocount = state->getDouble("VERTICAL_AUTOCOUNT");
296 	double horizontal_autorefer = state->getDouble("HORIZONTAL_AUTOREFER");
297 	double vertical_autorefer = state->getDouble("VERTICAL_AUTOREFER");
298 
299 	if (isUndo)
300 	{
301 		this->LeftPg = left_old;
302 		this->setPageName(name_old);
303 		this->m_pageSize = size_old;
304 		this->setOrientation(orientation_old);
305 		this->setWidth(width_old);
306 		this->setHeight(height_old);
307 		this->setInitialHeight(init_height_old);
308 		this->setInitialWidth(init_width_old);
309 		this->initialMargins.setTop(init_margin_top_old);
310 		this->initialMargins.setBottom(init_margin_bottom_old);
311 		this->initialMargins.setLeft(init_margin_left_old);
312 		this->initialMargins.setRight(init_margin_right_old);
313 		this->marginPreset = margin_preset_old;
314 		this->Margins.setTop(margin_top_old);
315 		this->Margins.setBottom(margin_bottom_old);
316 		this->guides.setHorizontalAutoGap(horizontal_autogap_old);
317 		this->guides.setVerticalAutoGap(vertical_autogap_old);
318 		this->guides.setHorizontalAutoCount(horizontal_autocount_old);
319 		this->guides.setVerticalAutoCount(vertical_autocount_old);
320 		this->guides.setHorizontalAutoRefer(horizontal_autorefer_old);
321 		this->guides.setVerticalAutoRefer(vertical_autorefer_old);
322 	}
323 	else
324 	{
325 		this->LeftPg = left;
326 		this->setPageName(name);
327 		this->m_pageSize = size;
328 		this->setOrientation(orientation);
329 		this->setWidth(width);
330 		this->setHeight(height);
331 		this->setInitialHeight(init_height);
332 		this->setInitialWidth(init_width);
333 		this->initialMargins.setTop(init_margin_top);
334 		this->initialMargins.setBottom(init_margin_bottom);
335 		this->initialMargins.setLeft(init_margin_left);
336 		this->initialMargins.setRight(init_margin_right);
337 		this->marginPreset = margin_preset;
338 		this->Margins.setTop(margin_top);
339 		this->Margins.setBottom(margin_bottom);
340 		this->guides.setHorizontalAutoGap(horizontal_autogap);
341 		this->guides.setVerticalAutoGap(vertical_autogap);
342 		this->guides.setHorizontalAutoCount(horizontal_autocount);
343 		this->guides.setVerticalAutoCount(vertical_autocount);
344 		this->guides.setHorizontalAutoRefer(horizontal_autorefer);
345 		this->guides.setVerticalAutoRefer(vertical_autorefer);
346 	}
347 }
348 
restorePageItemCreation(ScItemState<PageItem * > * state,bool isUndo)349 void ScPage::restorePageItemCreation(ScItemState<PageItem*> *state, bool isUndo)
350 {
351 	if (!state)
352 		return;
353 	int stateCode = state->transactionCode;
354 	PageItem *ite = state->getItem();
355 	bool oldMPMode = m_Doc->masterPageMode();
356 	m_Doc->setMasterPageMode(!ite->OnMasterPage.isEmpty());
357 	if (m_Doc->inAnEditMode())
358 		m_Doc->view()->requestMode(modeNormal);
359 	m_Doc->m_Selection->delaySignalsOn();
360 	if (isUndo)
361 	{
362 		if (m_Doc->m_Selection->findItem(ite)!=-1)
363 		{
364 			if (m_Doc->appMode == modeEdit || m_Doc->appMode == modeEditTable)
365 				m_Doc->view()->requestMode(modeNormal);
366 			m_Doc->m_Selection->removeItem(ite);
367 		}
368 		if ((stateCode == 0) || (stateCode == 1))
369 			m_Doc->view()->deselectItems(true);
370 		Selection tmpSelection(m_Doc, false);
371 		tmpSelection.addItem(ite);
372 		m_Doc->itemSelection_DeleteItem(&tmpSelection);
373 	}
374 	else
375 	{
376 		if ((stateCode == 0) || (stateCode == 1))
377 			m_Doc->view()->deselectItems(true);
378 		m_Doc->Items->append(ite);
379 		ite->OwnPage = m_Doc->OnPage(ite);
380 	}
381 	if ((stateCode == 0) || (stateCode == 2))
382 		update();
383 	m_Doc->setMasterPageMode(oldMPMode);
384 	m_Doc->m_Selection->delaySignalsOff();
385 }
386 
restorePageItemDeletion(ScItemState<QList<PageItem * >> * state,bool isUndo)387 void ScPage::restorePageItemDeletion(ScItemState< QList<PageItem*> > *state, bool isUndo)
388 {
389 	if (!state)
390 		return;
391 
392 	int stateCode = state->transactionCode;
393 	QList<PageItem*> itemList = state->getItem();
394 	int id = state->getInt("ITEMID");
395 	int id2 = state->getInt("ID");
396 	if (itemList.count() <= 0)
397 		return;
398 	m_Doc->view()->deselectItems(true);
399 	bool oldMPMode = m_Doc->masterPageMode();
400 	m_Doc->setMasterPageMode(!itemList.at(0)->OnMasterPage.isEmpty());
401 	if (m_Doc->appMode == modeEditClip) // switch off from edit shape
402 		m_Doc->scMW()->nodePalette->EndEdit();
403 	m_Doc->m_Selection->delaySignalsOn();
404 	if (isUndo)
405 	{
406 		//CB #3373 reinsert at old position and renumber items
407 		PageItem* oldItem = itemList.at(id2);
408 		if (oldItem->Parent && oldItem->Parent->isGroup())
409 			oldItem->Parent->asGroupFrame()->groupItemList.insert(id, oldItem);
410 		else
411 			m_Doc->Items->insert(id, oldItem);
412 		m_Doc->m_Selection->addItems(itemList);
413 	}
414 	else
415 	{
416 		Selection tmpSelection(m_Doc, false);
417 		PageItem* ite = itemList.at(id2);
418 		if (m_Doc->m_Selection->findItem(ite) != -1)
419 		{
420 			if (m_Doc->appMode == modeEdit || m_Doc->appMode == modeEditTable)
421 				m_Doc->view()->requestMode(modeNormal);
422 			m_Doc->m_Selection->removeItem(ite);
423 		}
424 		tmpSelection.addItem(ite);
425 		m_Doc->itemSelection_DeleteItem(&tmpSelection);
426 	}
427 	if ((stateCode == 0) || (stateCode == 2))
428 		update();
429 	m_Doc->setMasterPageMode(oldMPMode);
430 	m_Doc->m_Selection->delaySignalsOff();
431 }
432 
restorePageItemConversion(ScItemState<QPair<PageItem *,PageItem * >> * state,bool isUndo)433 void ScPage::restorePageItemConversion(ScItemState<QPair<PageItem*, PageItem*> >* state, bool isUndo)
434 {
435 	if (!state)
436 		return;
437 
438 	PageItem *oldItem = state->getItem().first;
439 	PageItem *newItem = state->getItem().second;
440 	bool oldMPMode = m_Doc->masterPageMode();
441 	m_Doc->setMasterPageMode(!oldItem->OnMasterPage.isEmpty());
442 	if (isUndo)
443 	{
444 		m_Doc->Items->replace(m_Doc->Items->indexOf(newItem), oldItem);
445 		oldItem->updatePolyClip();
446 		m_Doc->adjustItemSize(oldItem);
447 		m_Doc->m_Selection->replaceItem(newItem, oldItem);
448 	}
449 	else
450 	{
451 		m_Doc->Items->replace(m_Doc->Items->indexOf(oldItem), newItem);
452 		m_Doc->m_Selection->replaceItem(oldItem, newItem);
453 	}
454 	m_Doc->setMasterPageMode(oldMPMode);
455 }
456 
restorePageItemConversionToSymbol(ScItemState<QPair<PageItem *,PageItem * >> * state,bool isUndo)457 void ScPage::restorePageItemConversionToSymbol(ScItemState<QPair<PageItem*, PageItem*> >* state, bool isUndo)
458 {
459 	//#11365... this code is not finished and broken... fixing will fix 11365
460 	if (!state)
461 		return;
462 
463 	PageItem *oldItem = state->getItem().first;
464 	PageItem *newItem = state->getItem().second;
465 	QString patternName = state->getDescription();
466 	bool oldMPMode = m_Doc->masterPageMode();
467 	m_Doc->setMasterPageMode(!oldItem->OnMasterPage.isEmpty());
468 	if (isUndo)
469 	{
470 		m_Doc->Items->replace(m_Doc->Items->indexOf(newItem), oldItem);
471 		oldItem->updatePolyClip();
472 		m_Doc->adjustItemSize(oldItem);
473 		if (m_Doc->docPatterns.contains(patternName))
474 			m_Doc->removePattern(patternName);
475 		m_Doc->m_Selection->replaceItem(newItem, oldItem);
476 	}
477 	else
478 	{
479 		m_Doc->Items->replace(m_Doc->Items->indexOf(oldItem), newItem);
480 		m_Doc->m_Selection->replaceItem(oldItem, newItem);
481 	}
482 	m_Doc->setMasterPageMode(oldMPMode);
483 }
484 
setXOffset(const double newCanvasXOffset)485 void ScPage::setXOffset(const double newCanvasXOffset)
486 {
487 	m_xOffset = newCanvasXOffset;
488 }
489 
setYOffset(const double newCanvasYOffset)490 void ScPage::setYOffset(const double newCanvasYOffset)
491 {
492 	m_yOffset = newCanvasYOffset;
493 }
494 
setWidth(const double newWidth)495 void ScPage::setWidth(const double newWidth)
496 {
497 	m_width = newWidth;
498 }
499 
setHeight(const double newHeight)500 void ScPage::setHeight(const double newHeight)
501 {
502 	m_height = newHeight;
503 }
504 
setInitialWidth(const double newInitialWidth)505 void ScPage::setInitialWidth(const double newInitialWidth)
506 {
507 	m_initialWidth = newInitialWidth;
508 }
509 
setInitialHeight(const double newInitialHeight)510 void ScPage::setInitialHeight(const double newInitialHeight)
511 {
512 	m_initialHeight = newInitialHeight;
513 }
514 
setOrientation(int ori)515 void ScPage::setOrientation(int ori)
516 {
517 	m_orientation = ori;
518 }
519 
setPageSectionNumber(const QString & newPageSectionNumber)520 void ScPage::setPageSectionNumber(const QString& newPageSectionNumber)
521 {
522 	m_pageSectionNumber=newPageSectionNumber;
523 }
524 
copySizingProperties(ScPage * sourcePage,const MarginStruct & pageMargins)525 void ScPage::copySizingProperties(ScPage* sourcePage, const MarginStruct& pageMargins)
526 {
527 	if (sourcePage == nullptr)
528 		return;
529 	m_pageSize = sourcePage->m_pageSize;
530 	m_orientation = sourcePage->m_orientation;
531 	m_width = sourcePage->m_width;
532 	m_height = sourcePage->m_height;
533 	m_initialWidth = sourcePage->m_initialWidth;
534 	m_initialHeight = sourcePage->m_initialHeight;
535 
536 	Margins = pageMargins;
537 	// #8859 do not get initialMargins from pageMargins otherwise
538 	// margins may be inverted when applying master pages
539 	initialMargins = sourcePage->initialMargins;
540 }
541