Subversion Repositories Scribus

Rev

Rev 24719 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

/*
For general Scribus (>=1.3.2) copyright and licensing information please refer
to the COPYING file provided with the program. Following this notice may exist
a copyright and/or license notice that predates the release of Scribus 1.3.2
for which a new license (GPL+exception) is in place.
*/

/***************************************************************************
                          scribusdoc.cpp  -  description
                             -------------------
    begin                : Fre Apr  6 21:47:55 CEST 2001
    copyright            : (C) 2001 by Franz Schmid
    email                : Franz.Schmid@altmuehlnet.de
 ***************************************************************************/


/***************************************************************************
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/


#include <cstdlib>
#include <memory>
#include <utility>
#include <sstream>

#include <QByteArray>
#include <QDebug>
#include <QDialog>
#include <QEventLoop>
#include <QFile>
#include <QList>
#include <QMessageBox>
#include <QPainter>
#include <QPixmap>
#include <QPointer>
#include <QProgressBar>
#include <QRandomGenerator>
#include <QRegExp>
#include <QtAlgorithms>
#include <QTime>
#include <QTransform>
//#include <qtconcurrentmap.h>

#include "actionmanager.h"
#include "text/boxes.h"
#include "canvas.h"
#include "colorblind.h"
#include "colormgmt/sccolormgmtenginefactory.h"
#include "commonstrings.h"
#include "desaxe/digester.h"
#include "fileloader.h"
#include "filewatcher.h"
#include "fpoint.h"
#include "hyphenator.h"
#include "langmgr.h"
#include "notesstyles.h"
#include "numeration.h"
#include "pageitem.h"
#include "pageitemiterator.h"
#include "pageitem_imageframe.h"
#include "pageitem_latexframe.h"
#include "pageitem_line.h"
#include "pageitem_noteframe.h"
#include "pageitem_pathtext.h"
#include "pageitem_polygon.h"
#include "pageitem_polyline.h"
#include "pageitem_table.h"
#include "pageitem_textframe.h"
#ifdef HAVE_OSG
        #include "pageitem_osgframe.h"
#endif
#include "pageitem_arc.h"
#include "pageitem_group.h"
#include "pageitem_regularpolygon.h"
#include "pageitem_spiral.h"
#include "pageitem_symbol.h"
#include "pagesize.h"
#include "pagestructs.h"
#include "pdfwriter.h"
#include "prefsfile.h"
#include "prefsmanager.h"
#include "resourcecollection.h"
#include "scclocale.h"
#include "sccolorengine.h"
#include "sclimits.h"
#include "scpage.h"
#include "scpainter.h"
#include "scraction.h"
#include "scribusXml.h"
#include "scribuscore.h"
#include "scribusdoc.h"
#include "scribusview.h"
#include "scribuswin.h"
#include "selection.h"
#include "serializer.h"
#include "tableborder.h"
#include "textnote.h"
#include "text/textlayoutpainter.h"
#include "text/textshaper.h"
#include "ui/guidemanager.h"
#include "ui/hruler.h"
#include "ui/inserttablecolumnsdialog.h"
#include "ui/inserttablerowsdialog.h"
#include "ui/layers.h"
#include "ui/mark2item.h"
#include "ui/mark2mark.h"
#include "ui/markanchor.h"
#include "ui/markinsert.h"
#include "ui/marksmanager.h"
#include "ui/markvariabletext.h"
#include "ui/notesstyleseditor.h"
#include "ui/outlinepalette.h"
#include "ui/pagepalette.h"
#include "ui/storyeditor.h"
#include "ui/tablecolumnwidthsdialog.h"
#include "ui/tablerowheightsdialog.h"
#include "undomanager.h"
#include "units.h"
#include "util.h"
#include "util_math.h"
#include "util_printer.h"


// static const bool FRAMESELECTION_EDITS_DEFAULTSTYLE = false;



/**
 This class forwards change events for pages and pageitems to
 the region occupied by this page or pageitem.
 */

class DocUpdater : public Observer<ScPage*>, public Observer<PageItem*>
{
        ScribusDoc* doc;
        int  m_updateEnabled;
        bool m_docChangeNeeded;
public:
        DocUpdater(ScribusDoc* d) : doc(d), m_updateEnabled(0), m_docChangeNeeded(false) {}

        bool inUpdateSession() const
        {
                return m_updateEnabled > 0;
        }

        void beginUpdate()
        {
                if (m_updateEnabled == 0)
                        m_docChangeNeeded = false;
                ++m_updateEnabled;
        }

        void endUpdate()
        {
                --m_updateEnabled;
                if (m_updateEnabled <= 0)
                {
                        if (m_docChangeNeeded)
                        {
                                doc->changed();
                                m_docChangeNeeded = false;
                        }
                }
        }
       
        void changed(ScPage* pg, bool /*doLayout*/) override
        {
                QRectF pagebox(pg->xOffset(), pg->yOffset(), pg->width(), pg->height());
                doc->invalidateRegion(pagebox);
                doc->regionsChanged()->update(pagebox);
                if (m_updateEnabled <= 0)
                {
                        doc->changed();
                        return;
                }
                m_docChangeNeeded = true;
        }
       
        void changed(PageItem* it, bool doLayout) override
        {
                it->invalidateLayout();
                if (doLayout)
                        it->layout();
                double x, y, w, h;
                QTransform t = it->getTransform();
                w = it->visualWidth();
                h = it->visualHeight();
                x = -it->visualLineWidth() / 2.0;
                y = -it->visualLineWidth() / 2.0;
                QRectF upRect = t.mapRect(QRectF(x, y, w, h));
                doc->regionsChanged()->update(upRect);
                if (m_updateEnabled <= 0)
                {
                        doc->changed();
                        return;
                }
                m_docChangeNeeded = true;
        }

        void setDocChangeNeeded(bool changeNeeded = true)
        {
                m_docChangeNeeded = changeNeeded;
        }
};




ScribusDoc::ScribusDoc() : UndoObject( tr("Document")), Observable<ScribusDoc>(nullptr),
        m_appPrefsData(PrefsManager::instance().appPrefs),
        m_docPrefsData(PrefsManager::instance().appPrefs),
        m_undoManager(UndoManager::instance()),
        m_automaticTextFrames(false),
        m_guardedObject(this),
        m_documentFileName( tr("Document") + "-"),
        minCanvasCoordinate(FPoint(0, 0)),
        m_Selection(new Selection(this, true)),
        PageSp(1), PageSpa(0),
        FirstPnum(1),
        PageColors(this, true),
        AllFonts(&m_appPrefsData.fontPrefs.AvailFonts),
        colorEngine(ScCore->defaultEngine),
        autoSaveTimer(new QTimer(this)),
        m_itemCreationTransaction(nullptr),
        m_alignTransaction(nullptr)
{
        m_docUnitRatio = unitGetRatioFromIndex(m_docPrefsData.docSetupPrefs.docUnitIndex);
        m_docPrefsData.docSetupPrefs.pageHeight = 0;
        m_docPrefsData.docSetupPrefs.pageWidth = 0;
        m_docPrefsData.docSetupPrefs.pagePositioning = 0;
        maxCanvasCoordinate = FPoint(m_docPrefsData.displayPrefs.scratch.left() + m_docPrefsData.displayPrefs.scratch.right(), m_docPrefsData.displayPrefs.scratch.top() + m_docPrefsData.displayPrefs.scratch.bottom());
        init();
        //create default numeration
        auto* numS = new NumStruct;
        numS->m_name = "default";
        Numeration newNum;
        newNum.suffix = ".";
        numS->m_nums.insert(0, newNum);
        numS->m_counters.insert(0, 0);
        numS->m_lastlevel = -1;
        numerations.insert("default", numS);
}


ScribusDoc::ScribusDoc(const QString& docName, int unitindex, const PageSize& pagesize, const MarginStruct& margins, const DocPagesSetup& pagesSetup) : UndoObject( tr("Document")),
        m_appPrefsData(PrefsManager::instance().appPrefs),
        m_docPrefsData(PrefsManager::instance().appPrefs),
        m_undoManager(UndoManager::instance()),
        m_docUnitRatio(unitGetRatioFromIndex(m_appPrefsData.docSetupPrefs.docUnitIndex)),
        m_automaticTextFrames(pagesSetup.autoTextFrames),
        m_guardedObject(this),
        m_documentFileName(docName),
        minCanvasCoordinate(FPoint(0, 0)),
        m_Selection(new Selection(this, true)),
        PageSp(pagesSetup.columnCount), PageSpa(pagesSetup.columnDistance),
        FirstPnum(pagesSetup.firstPageNumber),
        PageColors(this, true),
        AllFonts(&m_appPrefsData.fontPrefs.AvailFonts),
        colorEngine(ScCore->defaultEngine),
        autoSaveTimer(new QTimer(this)),
        m_itemCreationTransaction(nullptr),
        m_alignTransaction(nullptr)
{
        m_docPrefsData.docSetupPrefs.docUnitIndex = unitindex;
        m_docPrefsData.docSetupPrefs.pageHeight = pagesize.height();
        m_docPrefsData.docSetupPrefs.pageWidth = pagesize.width();
        m_docPrefsData.docSetupPrefs.pageSize = pagesize.name();
        m_docPrefsData.docSetupPrefs.margins = margins;
        maxCanvasCoordinate = FPoint(m_docPrefsData.displayPrefs.scratch.left() + m_docPrefsData.displayPrefs.scratch.right(), m_docPrefsData.displayPrefs.scratch.top() + m_docPrefsData.displayPrefs.scratch.bottom());
        setPageSetFirstPage(pagesSetup.pageArrangement, pagesSetup.firstPageLocation);
        init();
        m_docPrefsData.docSetupPrefs.pageOrientation = pagesSetup.orientation;
        m_docPrefsData.docSetupPrefs.pagePositioning = pagesSetup.pageArrangement;
}


void ScribusDoc::init()
{
        Q_CHECK_PTR(m_Selection);
        Q_CHECK_PTR(autoSaveTimer);

        m_docPrefsData.colorPrefs.DCMSset.CMSinUse = false;

        colorEngine = ScCore->defaultEngine;
        SetDefaultCMSParams();

        // init update change management
        setUpdateManager(&m_updateManager);
        m_itemsChanged.setUpdateManager(&m_updateManager);
        m_pagesChanged.setUpdateManager(&m_updateManager);
        m_regionsChanged.setUpdateManager(&m_updateManager);
        nodeEdit.setUpdateManager(&m_updateManager);
       
        // setup update() event chains
        m_docUpdater = new DocUpdater(this);
        m_itemsChanged.connectObserver(m_docUpdater);
        m_pagesChanged.connectObserver(m_docUpdater);

        PrefsManager& prefsManager = PrefsManager::instance();
        m_docPrefsData.colorPrefs.DCMSset = prefsManager.appPrefs.colorPrefs.DCMSset;

        Print_Options.firstUse = true;
        PrinterUtil::getDefaultPrintOptions(Print_Options, m_docPrefsData.docSetupPrefs.bleeds);
        Print_Options.bleeds = m_docPrefsData.docSetupPrefs.bleeds;
        Print_Options.useDocBleeds = true;

        m_docPrefsData.pdfPrefs.firstUse = true;
        m_docPrefsData.pdfPrefs.Version = m_appPrefsData.pdfPrefs.Version;
        m_docPrefsData.pdfPrefs.SolidProf = m_docPrefsData.colorPrefs.DCMSset.DefaultSolidColorRGBProfile;
        m_docPrefsData.pdfPrefs.ImageProf = m_docPrefsData.colorPrefs.DCMSset.DefaultImageRGBProfile;
        m_docPrefsData.pdfPrefs.PrintProf = m_docPrefsData.colorPrefs.DCMSset.DefaultPrinterProfile;
        m_docPrefsData.pdfPrefs.Intent  = m_docPrefsData.colorPrefs.DCMSset.DefaultIntentColors;
        m_docPrefsData.pdfPrefs.Intent2 = m_docPrefsData.colorPrefs.DCMSset.DefaultIntentImages;
        m_docPrefsData.pdfPrefs.useDocBleeds = true;
        m_docPrefsData.pdfPrefs.bleeds = m_docPrefsData.docSetupPrefs.bleeds;

        AddFont(m_appPrefsData.itemToolPrefs.textFont);//, prefsData.AvailFonts[prefsData.itemToolPrefs.textFont]->Font);
        //FIXME: aren't we doing this now anyway with prefs struct copy?
        m_docPrefsData.itemToolPrefs.textFont = m_appPrefsData.itemToolPrefs.textFont;
        m_docPrefsData.itemToolPrefs.textSize = m_appPrefsData.itemToolPrefs.textSize;
        m_docPrefsData.itemToolPrefs.textTabFillChar = m_appPrefsData.itemToolPrefs.textTabFillChar;
        m_docPrefsData.opToolPrefs.dispX = m_appPrefsData.opToolPrefs.dispX;
        m_docPrefsData.opToolPrefs.dispY = m_appPrefsData.opToolPrefs.dispY;
        m_docPrefsData.opToolPrefs.constrain = m_appPrefsData.opToolPrefs.constrain;

        PageColors.ensureDefaultColors();
        if (m_appPrefsData.itemToolPrefs.shapeLineColor != CommonStrings::None)
                PageColors.insert(m_appPrefsData.itemToolPrefs.shapeLineColor, m_appPrefsData.colorPrefs.DColors[m_appPrefsData.itemToolPrefs.shapeLineColor]);
        m_docPrefsData.itemToolPrefs.shapeLineColor = m_appPrefsData.itemToolPrefs.shapeLineColor;
        if (m_appPrefsData.itemToolPrefs.lineColor != CommonStrings::None)
                PageColors.insert(m_appPrefsData.itemToolPrefs.lineColor, m_appPrefsData.colorPrefs.DColors[m_appPrefsData.itemToolPrefs.lineColor]);
        m_docPrefsData.itemToolPrefs.lineColor = m_appPrefsData.itemToolPrefs.lineColor;
        if (m_appPrefsData.itemToolPrefs.textColor != CommonStrings::None)
                PageColors.insert(m_appPrefsData.itemToolPrefs.textColor, m_appPrefsData.colorPrefs.DColors[m_appPrefsData.itemToolPrefs.textColor]);
        m_docPrefsData.itemToolPrefs.textColor = m_appPrefsData.itemToolPrefs.textColor;
        if (m_appPrefsData.itemToolPrefs.textStrokeColor != CommonStrings::None)
                PageColors.insert(m_appPrefsData.itemToolPrefs.textStrokeColor, m_appPrefsData.colorPrefs.DColors[m_appPrefsData.itemToolPrefs.textStrokeColor]);
        m_docPrefsData.itemToolPrefs.textStrokeColor = m_appPrefsData.itemToolPrefs.textStrokeColor;
        if (m_appPrefsData.itemToolPrefs.shapeFillColor != CommonStrings::None)
                PageColors.insert(m_appPrefsData.itemToolPrefs.shapeFillColor, m_appPrefsData.colorPrefs.DColors[m_appPrefsData.itemToolPrefs.shapeFillColor]);
        m_docPrefsData.itemToolPrefs.shapeFillColor = m_appPrefsData.itemToolPrefs.shapeFillColor;
        if (m_appPrefsData.itemToolPrefs.imageFillColor != CommonStrings::None)
                PageColors.insert(m_appPrefsData.itemToolPrefs.imageFillColor, m_appPrefsData.colorPrefs.DColors[m_appPrefsData.itemToolPrefs.imageFillColor]);
        m_docPrefsData.itemToolPrefs.imageFillColor = m_appPrefsData.itemToolPrefs.imageFillColor;
        if (m_appPrefsData.itemToolPrefs.imageStrokeColor != CommonStrings::None)
                PageColors.insert(m_appPrefsData.itemToolPrefs.imageStrokeColor, m_appPrefsData.colorPrefs.DColors[m_appPrefsData.itemToolPrefs.imageStrokeColor]);
        m_docPrefsData.itemToolPrefs.imageStrokeColor = m_appPrefsData.itemToolPrefs.imageStrokeColor;
        if (m_appPrefsData.itemToolPrefs.textFillColor != CommonStrings::None)
                PageColors.insert(m_appPrefsData.itemToolPrefs.textFillColor, m_appPrefsData.colorPrefs.DColors[m_appPrefsData.itemToolPrefs.textFillColor]);
        m_docPrefsData.itemToolPrefs.textFillColor = m_appPrefsData.itemToolPrefs.textFillColor;
        if (m_appPrefsData.itemToolPrefs.textLineColor != CommonStrings::None)
                PageColors.insert(m_appPrefsData.itemToolPrefs.textLineColor, m_appPrefsData.colorPrefs.DColors[m_appPrefsData.itemToolPrefs.textLineColor]);
        if (m_appPrefsData.itemToolPrefs.calligraphicPenFillColor != CommonStrings::None)
                PageColors.insert(m_appPrefsData.itemToolPrefs.calligraphicPenFillColor, m_appPrefsData.colorPrefs.DColors[m_appPrefsData.itemToolPrefs.calligraphicPenFillColor]);
        if (m_appPrefsData.itemToolPrefs.calligraphicPenLineColor != CommonStrings::None)
                PageColors.insert(m_appPrefsData.itemToolPrefs.calligraphicPenLineColor, m_appPrefsData.colorPrefs.DColors[m_appPrefsData.itemToolPrefs.calligraphicPenLineColor]);
       
        ParagraphStyle pstyle;
        pstyle.setDefaultStyle(true);
        pstyle.setName(CommonStrings::DefaultParagraphStyle);
        pstyle.setLineSpacingMode(ParagraphStyle::FixedLineSpacing);
        pstyle.setLineSpacing(15);
        pstyle.setAlignment(ParagraphStyle::LeftAligned);
        pstyle.setDirection(ParagraphStyle::LTR);
        pstyle.setLeftMargin(0);
        pstyle.setFirstIndent(0);
        pstyle.setRightMargin(0);
        pstyle.setGapBefore(0);
        pstyle.setGapAfter(0);
        pstyle.setHasDropCap(false);
        pstyle.setHasBullet(false);
        pstyle.setHasNum(false);
        pstyle.setHyphenConsecutiveLines(2);
        pstyle.setDropCapLines(2);
        pstyle.setParEffectOffset(0);
        pstyle.setBackgroundColor(CommonStrings::None);
        pstyle.setBackgroundShade(100);
        pstyle.charStyle().setParent("");
       
        CharStyle cstyle;
        cstyle.setDefaultStyle(true);
        cstyle.setName(CommonStrings::DefaultCharacterStyle);
        cstyle.setFont(m_appPrefsData.fontPrefs.AvailFonts[m_docPrefsData.itemToolPrefs.textFont]);
        cstyle.setFontSize(m_docPrefsData.itemToolPrefs.textSize);
        cstyle.setFontFeatures("");
        cstyle.setFeatures(QStringList(CharStyle::INHERIT));
        cstyle.setHyphenWordMin(3);
        cstyle.setFillColor(m_docPrefsData.itemToolPrefs.textColor);
        cstyle.setFillShade(m_docPrefsData.itemToolPrefs.textShade);
        cstyle.setStrokeColor(m_docPrefsData.itemToolPrefs.textStrokeColor);
        cstyle.setStrokeShade(m_docPrefsData.itemToolPrefs.textStrokeShade);
        cstyle.setBackColor(CommonStrings::None);
        cstyle.setBackShade(100);
        cstyle.setBaselineOffset(0);
        cstyle.setShadowXOffset(50);
        cstyle.setShadowYOffset(-50);
        cstyle.setOutlineWidth(10);
        cstyle.setUnderlineOffset(m_docPrefsData.typoPrefs.valueUnderlinePos);
        cstyle.setUnderlineWidth(m_docPrefsData.typoPrefs.valueUnderlineWidth);
        cstyle.setStrikethruOffset(m_docPrefsData.typoPrefs.valueStrikeThruPos);
        cstyle.setStrikethruWidth(m_docPrefsData.typoPrefs.valueStrikeThruPos);
        cstyle.setScaleH(1000);
        cstyle.setScaleV(1000);
        cstyle.setTracking(0);
        cstyle.setLanguage(PrefsManager::instance().appPrefs.docSetupPrefs.language);
       
        m_docParagraphStyles.create(pstyle);
        m_docParagraphStyles.makeDefault( &(m_docParagraphStyles[0]) );
       
        m_docCharStyles.create(cstyle);
        m_docCharStyles.makeDefault( &(m_docCharStyles[0]) );
       
        m_docParagraphStyles[0].breakImplicitCharStyleInheritance();
        m_docParagraphStyles[0].charStyle().setContext( & m_docCharStyles );
//      docParagraphStyles[0].charStyle().setName( "cdocdefault" ); // DON'T TRANSLATE

        currentStyle = pstyle;

        // Create default table style.
        // TODO: We should have preferences for the default values.
        TableStyle defaultTableStyle;
        defaultTableStyle.setDefaultStyle(true);
        defaultTableStyle.setName(CommonStrings::DefaultTableStyle);
        defaultTableStyle.setFillColor(CommonStrings::None);
        defaultTableStyle.setFillShade(100);
        defaultTableStyle.setLeftBorder(TableBorder(1.0, Qt::SolidLine, "Black", 100));
        defaultTableStyle.setRightBorder(TableBorder(1.0, Qt::SolidLine, "Black", 100));
        defaultTableStyle.setTopBorder(TableBorder(1.0, Qt::SolidLine, "Black", 100));
        defaultTableStyle.setBottomBorder(TableBorder(1.0, Qt::SolidLine, "Black", 100));
        m_docTableStyles.create(defaultTableStyle);
        m_docTableStyles.makeDefault(&(m_docTableStyles[0]));

        // Create default table cell style.
        // TODO: We should have preferences for the default values.
        CellStyle defaultCellStyle;
        defaultCellStyle.setDefaultStyle(true);
        defaultCellStyle.setName(CommonStrings::DefaultCellStyle);
        defaultCellStyle.setFillColor(CommonStrings::None);
        defaultCellStyle.setFillShade(100);
        defaultCellStyle.setLeftBorder(TableBorder(1.0, Qt::SolidLine, "Black", 100));
        defaultCellStyle.setRightBorder(TableBorder(1.0, Qt::SolidLine, "Black", 100));
        defaultCellStyle.setTopBorder(TableBorder(1.0, Qt::SolidLine, "Black", 100));
        defaultCellStyle.setBottomBorder(TableBorder(1.0, Qt::SolidLine, "Black", 100));
        defaultCellStyle.setLeftPadding(1.0);
        defaultCellStyle.setRightPadding(1.0);
        defaultCellStyle.setTopPadding(1.0);
        defaultCellStyle.setBottomPadding(1.0);
        m_docCellStyles.create(defaultCellStyle);
        m_docCellStyles.makeDefault(&(m_docCellStyles[0]));
       
        Layers.addLayer( tr("Background") );
        // FIXME: Check PDF version input
        //TODO: Check if this is needed now we use appPrefsData --> docPrefsData
        docPatterns.clear();
        docGradients.clear();

        if (autoSave() && ScCore->usingGUI())
                autoSaveTimer->start(autoSaveTime());
        //Do this after all the collections have been created and cleared!
        m_masterPageMode = true; // quick hack to force the change of pointers in setMasterPageMode();
        setMasterPageMode(false);
        addSymbols();
        //for loading old documents where default notes style is not saved
        if (m_docNotesStylesList.isEmpty())
                m_docNotesStylesList.append(new NotesStyle());
}


ScribusDoc::~ScribusDoc()
{
        m_guardedObject.nullify();
        CloseCMSProfiles();
        ScCore->fileWatcher->stop();
        ScCore->fileWatcher->removeFile(m_documentFileName);
        QList<PageItem*> allItems;
        for (int i = 0; i < DocItems.count(); ++i)
        {
                PageItem *currItem = DocItems.at(i);
                if (currItem->isGroup())
                        allItems = currItem->getAllChildren();
                else
                        allItems.append(currItem);
                for (int j = 0; j < allItems.count(); j++)
                {
                        currItem = allItems.at(j);
                        if (currItem->imageIsAvailable)
                                ScCore->fileWatcher->removeFile(currItem->Pfile);
                        if ((currItem->isImageFrame()) && (!currItem->Pfile.isEmpty()))
                        {
                                QFileInfo fi(currItem->Pfile);
                                ScCore->fileWatcher->removeDir(fi.absolutePath());
                        }
                }
                allItems.clear();
        }
        for (int i = 0; i < MasterItems.count(); ++i)
        {
                PageItem *currItem = MasterItems.at(i);
                if (currItem->isGroup())
                        allItems = currItem->getAllChildren();
                else
                        allItems.append(currItem);
                for (int j = 0; j < allItems.count(); j++)
                {
                        currItem = allItems.at(j);
                        if (currItem->imageIsAvailable)
                                ScCore->fileWatcher->removeFile(currItem->Pfile);
                        if ((currItem->isImageFrame()) && (!currItem->Pfile.isEmpty()))
                        {
                                QFileInfo fi(currItem->Pfile);
                                ScCore->fileWatcher->removeDir(fi.absolutePath());
                        }
                }
                allItems.clear();
        }
        for (auto itf = FrameItems.begin(); itf != FrameItems.end(); ++itf)
        {
                PageItem *currItem = itf.value();
                if (currItem->isGroup())
                        allItems = currItem->getAllChildren();
                else
                        allItems.append(currItem);
                for (int ii = 0; ii < allItems.count(); ii++)
                {
                        currItem = allItems.at(ii);
                        if (currItem->imageIsAvailable)
                                ScCore->fileWatcher->removeFile(currItem->Pfile);
                        if ((currItem->isImageFrame()) && (!currItem->Pfile.isEmpty()))
                        {
                                QFileInfo fi(currItem->Pfile);
                                ScCore->fileWatcher->removeDir(fi.absolutePath());
                        }
                }
                allItems.clear();
        }
        auto patternEnd = docPatterns.end();
        for (auto it = docPatterns.begin(); it != patternEnd; ++it)
        {
                ScPattern& pa = it.value();
                for (int j = 0; j < pa.items.count(); j++)
                {
                        PageItem *currItem = pa.items.at(j);
                        if (currItem->isGroup())
                                allItems = currItem->getAllChildren();
                        else
                                allItems.append(currItem);
                        for (int k = 0; k < allItems.count(); k++)
                        {
                                currItem = allItems.at(k);
                                if (currItem->itemType() == PageItem::ImageFrame)
                                {
                                        if ((currItem->imageIsAvailable) && (!currItem->Pfile.isEmpty()))
                                        {
                                                ScCore->fileWatcher->removeFile(currItem->Pfile);
                                                QFileInfo fi(currItem->Pfile);
                                                ScCore->fileWatcher->removeDir(fi.absolutePath());
                                        }
                                }
                        }
                        allItems.clear();
                }
                while (!pa.items.isEmpty())
                {
                        delete pa.items.takeFirst();
                }
        }
        //deleting resources allocated for marks and notes
        while (! m_docNotesList.isEmpty())
                delete m_docNotesList.takeFirst();
        while (!m_docMarksList.isEmpty())
                delete m_docMarksList.takeFirst();
        while (! m_docNotesStylesList.isEmpty())
                delete m_docNotesStylesList.takeFirst();
        docPatterns.clear();
        docGradients.clear();

        for (NumStruct* ns : numerations.values())
                delete ns;
        numerations.clear();

        while (!DocItems.isEmpty())
                delete DocItems.takeFirst();

        QList<PageItem*> tmList = FrameItems.values();
        while (!tmList.isEmpty())
                delete tmList.takeFirst();
        FrameItems.clear();

        while (!MasterPages.isEmpty())
                delete MasterPages.takeFirst();

        while (!DocPages.isEmpty())
                delete DocPages.takeFirst();

        while (!MasterItems.isEmpty())
                delete MasterItems.takeFirst();

        for (auto it3 = UsedFonts.begin(); it3 != UsedFonts.end(); ++it3)
        {
                if (!(*AllFonts)[it3.key()].localForDocument().isEmpty())
                        (*AllFonts).removeFont(it3.key());
                else
                        (*AllFonts)[it3.key()].decreaseUsage();
        }
        delete docHyphenator;
        delete m_serializer;
        delete m_tserializer;
        delete m_docUpdater;
        if (!m_docPrefsData.docSetupPrefs.AutoSaveKeep)
        {
                if (autoSaveFiles.count() != 0)
                {
                        for (int i = 0; i < autoSaveFiles.count(); i++)
                        {
                                QFile f(autoSaveFiles[i]);
                                f.remove();
                        }
                        autoSaveFiles.clear();
                }
        }
        ScCore->fileWatcher->start();
}

bool ScribusDoc::inAnEditMode() const
{
        return appMode == modeDrawBezierLine ||
                        appMode == modeEdit ||
                        appMode == modeEditArc ||
                        appMode == modeEditClip ||
                        appMode == modeEditGradientVectors ||
                        appMode == modeEditMeshGradient ||
                        appMode == modeEditMeshPatch ||
                        appMode == modeEditPolygon ||
                        appMode == modeEditSpiral ||
                        appMode == modeEditTable ||
                        appMode == modeEditWeldPoint;
}

bool ScribusDoc::inASpecialEditMode() const
{ // #12897, modes that use setSpecialEditMode() function in appmodehelper.cpp
        return appMode == modeDrawBezierLine ||
                        appMode == modeEditArc ||
                        appMode == modeEditGradientVectors ||
                        appMode == modeEditMeshGradient ||
                        appMode == modeEditMeshPatch ||
                        appMode == modeEditPolygon ||
                        appMode == modeEditSpiral ||
                        appMode == modeEditWeldPoint;
}

QList<PageItem*> ScribusDoc::getAllItems(QList<PageItem*> &items) const
{
        QList<PageItem*> ret;
        for (int em = 0; em < items.count(); ++em)
        {
                PageItem* embedded = items.at(em);
                ret.append(embedded);
                if (embedded->isGroup())
                        ret += embedded->getAllChildren();
        }
        return ret;
}

QList<PageItem*> *ScribusDoc::parentGroup(PageItem* item, QList<PageItem*> *list)
{
        QList<PageItem*> *retList = nullptr;
        if (list->contains(item))
                retList = list;
        else
        {
                for (int i = 0; i < list->count(); ++i)
                {
                        PageItem* embedded = list->at(i);
                        if (embedded->isGroup())
                        {
                                retList = parentGroup(item, &embedded->asGroupFrame()->groupItemList);
                                if (retList != nullptr)
                                        break;
                        }
                }
        }
        return retList;
}

void ScribusDoc::setup(int unitIndex, int fp, int firstLeft, int orientation, int firstPageNumber, const QString& defaultPageSize, const QString& documentName)
{
        m_docPrefsData.docSetupPrefs.docUnitIndex=unitIndex;
        setPageSetFirstPage(fp, firstLeft);
        m_docPrefsData.docSetupPrefs.pageOrientation = orientation;
        m_docPrefsData.docSetupPrefs.pageSize = defaultPageSize;
        FirstPnum = firstPageNumber;
        m_docPrefsData.docSetupPrefs.pagePositioning = fp;
        setDocumentFileName(documentName);
        HasCMS = false;
        if (!pdfOptions().UseLPI)
        {
                pdfOptions().LPISettings.clear();
                struct LPIData lpo;
                lpo.Frequency = 133;
                lpo.SpotFunc = 3;
                lpo.Angle = 105;
                pdfOptions().LPISettings.insert("Cyan", lpo);
                lpo.Angle = 75;
                pdfOptions().LPISettings.insert("Magenta", lpo);
                lpo.Angle = 90;
                pdfOptions().LPISettings.insert("Yellow", lpo);
                lpo.Angle = 45;
                pdfOptions().LPISettings.insert("Black", lpo);
                m_ActiveLayer = 0;
        }

        appMode = modeNormal;
        PrefsManager& prefsManager=PrefsManager::instance();

        m_docPrefsData.colorPrefs.DCMSset = prefsManager.appPrefs.colorPrefs.DCMSset;
        m_docPrefsData.pdfPrefs.SolidProf = m_docPrefsData.colorPrefs.DCMSset.DefaultSolidColorRGBProfile;
        m_docPrefsData.pdfPrefs.ImageProf = m_docPrefsData.colorPrefs.DCMSset.DefaultImageRGBProfile;
        m_docPrefsData.pdfPrefs.PrintProf = m_docPrefsData.colorPrefs.DCMSset.DefaultPrinterProfile;
        m_docPrefsData.pdfPrefs.Intent  = m_docPrefsData.colorPrefs.DCMSset.DefaultIntentColors;
        m_docPrefsData.pdfPrefs.Intent2 = m_docPrefsData.colorPrefs.DCMSset.DefaultIntentImages;
        BlackPoint   = m_docPrefsData.colorPrefs.DCMSset.BlackPoint;
        SoftProofing = m_docPrefsData.colorPrefs.DCMSset.SoftProofOn;
        Gamut        = m_docPrefsData.colorPrefs.DCMSset.GamutCheck;
        IntentColors = m_docPrefsData.colorPrefs.DCMSset.DefaultIntentColors;
        IntentImages = m_docPrefsData.colorPrefs.DCMSset.DefaultIntentImages;
        if (ScCore->haveCMS() && m_docPrefsData.colorPrefs.DCMSset.CMSinUse)
        {
                if (OpenCMSProfiles(ScCore->InputProfiles, ScCore->InputProfilesCMYK, ScCore->MonitorProfiles, ScCore->PrinterProfiles))
                {
                        HasCMS = true;
                        pdfOptions().SComp = m_docPrefsData.colorPrefs.DCMSset.ComponentsInput2;
                }
                else
                {
                        SetDefaultCMSParams();
                        HasCMS = false;
                }
        }
}


void ScribusDoc::setGUI(bool hasgui, ScribusMainWindow* mw, ScribusView* view)
{
        m_hasGUI = hasgui;
        m_ScMW = mw;
        //FIXME: stop using m_View
        m_View = view;
}

void ScribusDoc::createHyphenator()
{
        if (m_hasGUI)
        {
                if (docHyphenator)
                        return;
                docHyphenator = new Hyphenator(m_ScMW, this);
                Q_CHECK_PTR(docHyphenator);
        }
        else
                docHyphenator = nullptr;
}


void ScribusDoc::setLoading(bool docLoading)
{
        m_loading = docLoading;
}


bool ScribusDoc::isLoading() const
{
        return m_loading;
}


//AV: eeks. That should not be used
ScribusView* ScribusDoc::view() const
{
        return m_View;
}


const ScGuardedPtr<ScribusDoc>& ScribusDoc::guardedPtr() const
{
        return m_guardedObject;
}


void ScribusDoc::CloseCMSProfiles()
{
        HasCMS = false;
        SetDefaultCMSParams();
}

void ScribusDoc::SetDefaultCMSParams()
{
        BlackPoint     = true;
        SoftProofing   = false;
        Gamut          = false;
        IntentColors   = Intent_Relative_Colorimetric;
        IntentImages   = Intent_Relative_Colorimetric;
        DocInputRGBProf       = ScCore->defaultRGBProfile;
        DocInputCMYKProf      = ScCore->defaultCMYKProfile;
        DocInputImageRGBProf  = ScCore->defaultRGBProfile;
        DocInputImageCMYKProf = ScCore->defaultCMYKProfile;
        DocDisplayProf        = ScCore->defaultRGBProfile;
        DocPrinterProf        = ScCore->defaultCMYKProfile;
        stdTransRGBMon        = ScCore->defaultRGBToScreenSolidTrans;
        stdTransCMYKMon       = ScCore->defaultCMYKToRGBTrans;
        stdTransRGB           = ScCore->defaultCMYKToRGBTrans;
        stdTransCMYK          = ScCore->defaultRGBToCMYKTrans;
        stdProof              = ScCore->defaultRGBToScreenSolidTrans;
        stdProofGC            = ScCore->defaultRGBToScreenSolidTrans;
        stdProofCMYK          = ScCore->defaultCMYKToRGBTrans;
        stdProofCMYKGC        = ScCore->defaultCMYKToRGBTrans;
        stdTransImg           = ScCore->defaultRGBToScreenImageTrans;
        stdProofImg           = ScCore->defaultRGBToScreenImageTrans;
        stdProofImgCMYK       = ScCore->defaultCMYKToScreenImageTrans;
        stdLabToRGBTrans      = ScCore->defaultLabToRGBTrans;
        stdLabToCMYKTrans     = ScCore->defaultLabToCMYKTrans;
        stdLabToScreenTrans   = ScCore->defaultLabToScreenTrans;
        stdProofLab           = ScCore->defaultLabToRGBTrans;
        stdProofLabGC         = ScCore->defaultLabToRGBTrans;
}

bool ScribusDoc::OpenCMSProfiles(ProfilesL InPo, ProfilesL InPoCMYK, ProfilesL  /*MoPo*/, ProfilesL PrPo)
{
        HasCMS = false;
        ScColorProfile inputProf;

        colorEngine = colorMgmtEngineFactory.createDefaultEngine();
        ScColorMgmtStrategy colorStrategy;
        colorStrategy.setUseBlackPointCompensation(m_docPrefsData.colorPrefs.DCMSset.BlackPoint);
        colorStrategy.setUseBlackPreservation(false);
        colorEngine.setStrategy(colorStrategy);

        DocDisplayProf   = ScCore->monitorProfile;
        DocInputRGBProf  = colorEngine.openProfileFromFile( InPo[m_docPrefsData.colorPrefs.DCMSset.DefaultSolidColorRGBProfile] );
        DocInputCMYKProf = colorEngine.openProfileFromFile( InPoCMYK[m_docPrefsData.colorPrefs.DCMSset.DefaultSolidColorCMYKProfile] );
        DocPrinterProf   = colorEngine.openProfileFromFile( PrPo[m_docPrefsData.colorPrefs.DCMSset.DefaultPrinterProfile] );
        DocInputImageRGBProf  = colorEngine.openProfileFromFile( InPo[m_docPrefsData.colorPrefs.DCMSset.DefaultImageRGBProfile] );
        DocInputImageCMYKProf = colorEngine.openProfileFromFile( InPoCMYK[m_docPrefsData.colorPrefs.DCMSset.DefaultImageCMYKProfile] );
        if ((!DocDisplayProf) || (!DocInputRGBProf) || (!DocInputCMYKProf) || (!DocPrinterProf) || (!DocInputImageCMYKProf) || (!DocInputImageRGBProf))
        {
                m_docPrefsData.colorPrefs.DCMSset.CMSinUse = false;
                return false;
        }

        int dcmsFlags   = 0;
        int dcmsFlagsGC = 0;
        if (m_docPrefsData.colorPrefs.DCMSset.GamutCheck)
                dcmsFlagsGC |= Ctf_GamutCheck;
        if (m_docPrefsData.colorPrefs.DCMSset.BlackPoint)
        {
                dcmsFlags   |= Ctf_BlackPointCompensation;
                dcmsFlagsGC |= Ctf_BlackPointCompensation;
        }
        stdTransRGBMon  = colorEngine.createTransform(DocInputRGBProf, Format_RGB_16,
                                                                                DocDisplayProf, Format_RGB_16,
                                                                                IntentColors, dcmsFlags);
        stdTransCMYKMon = colorEngine.createTransform(DocInputCMYKProf, Format_CMYK_16,
                                                                                DocDisplayProf, Format_RGB_16,
                                                                                IntentColors, dcmsFlags);
        // TODO : check input profiles used for images
        stdProofImg = colorEngine.createProofingTransform(DocInputImageRGBProf, Format_BGRA_8,
                          DocDisplayProf, Format_BGRA_8, DocPrinterProf,
                          IntentImages, Intent_Relative_Colorimetric, dcmsFlagsGC);
        stdProofImgCMYK = colorEngine.createProofingTransform(DocInputImageCMYKProf, Format_CMYK_8,
                          DocDisplayProf, Format_BGRA_8, DocPrinterProf,
                          IntentImages, Intent_Relative_Colorimetric, dcmsFlagsGC);
        stdTransImg = colorEngine.createTransform(DocInputRGBProf, Format_BGRA_8,
                          DocDisplayProf, Format_BGRA_8,
                                          IntentImages, dcmsFlags);
        stdTransRGB = colorEngine.createTransform(DocInputCMYKProf, Format_CMYK_16,
                                          DocInputRGBProf, Format_RGB_16,
                                          IntentColors, dcmsFlags);
        stdTransCMYK = colorEngine.createTransform(DocInputRGBProf, Format_RGB_16,
                                          DocInputCMYKProf, Format_CMYK_16,
                                          IntentColors, dcmsFlags);

        ScColorProfile inputProfRGB;
        ScColorProfile inputProfCMYK;
        if (DocPrinterProf.colorSpace() == ColorSpace_Cmyk)
        {
                inputProf = (m_docPrefsData.colorPrefs.DCMSset.SoftProofOn && m_docPrefsData.colorPrefs.DCMSset.SoftProofFullOn) ? DocInputCMYKProf : DocPrinterProf;
                inputProfRGB  = DocInputRGBProf;
                inputProfCMYK = inputProf;
        }
        else
        {
                inputProf = (m_docPrefsData.colorPrefs.DCMSset.SoftProofOn && m_docPrefsData.colorPrefs.DCMSset.SoftProofFullOn) ? DocInputRGBProf : DocPrinterProf;
                inputProfRGB  = inputProf;
                inputProfCMYK = DocInputCMYKProf;
        }
        stdProof = colorEngine.createProofingTransform(inputProfRGB, Format_RGB_16,
                                                DocDisplayProf, Format_RGB_16,
                                                DocPrinterProf,
                                                IntentColors,
                                                Intent_Relative_Colorimetric, dcmsFlags);
        stdProofGC = colorEngine.createProofingTransform(inputProfRGB, Format_RGB_16,
                                                DocDisplayProf, Format_RGB_16,
                                                DocPrinterProf, IntentColors,
                                                Intent_Relative_Colorimetric, dcmsFlags| Ctf_GamutCheck);
        stdProofCMYK = colorEngine.createProofingTransform(inputProfCMYK, Format_CMYK_16,
                                                DocDisplayProf, Format_RGB_16,
                                                DocPrinterProf, IntentColors,
                                                Intent_Relative_Colorimetric, dcmsFlags);
        stdProofCMYKGC = colorEngine.createProofingTransform(inputProfCMYK, Format_CMYK_16,
                                                DocDisplayProf, Format_RGB_16,
                                                DocPrinterProf,
                                                IntentColors,
                                                Intent_Relative_Colorimetric, dcmsFlags | Ctf_GamutCheck);
        stdProofLab = colorEngine.createProofingTransform(ScCore->defaultLabProfile, Format_Lab_Dbl,
                                                DocDisplayProf, Format_RGB_16,
                                                DocPrinterProf,
                                                IntentColors,
                                                Intent_Relative_Colorimetric, dcmsFlags);
        stdProofLabGC = colorEngine.createProofingTransform(ScCore->defaultLabProfile, Format_Lab_Dbl,
                                                DocDisplayProf, Format_RGB_16,
                                                DocPrinterProf, IntentColors,
                                                Intent_Relative_Colorimetric, dcmsFlags| Ctf_GamutCheck);

        if (DocInputRGBProf.colorSpace() == ColorSpace_Rgb)
                        m_docPrefsData.colorPrefs.DCMSset.ComponentsInput2 = 3;
        if (DocInputRGBProf.colorSpace() == ColorSpace_Cmyk)
                        m_docPrefsData.colorPrefs.DCMSset.ComponentsInput2 = 4;
        if (DocInputRGBProf.colorSpace() == ColorSpace_Cmy)
                        m_docPrefsData.colorPrefs.DCMSset.ComponentsInput2 = 3;

        stdLabToRGBTrans  = colorEngine.createTransform(ScCore->defaultLabProfile, Format_Lab_Dbl, DocInputRGBProf, Format_RGB_16, Intent_Absolute_Colorimetric, dcmsFlags);
        stdLabToCMYKTrans = colorEngine.createTransform(ScCore->defaultLabProfile, Format_Lab_Dbl, DocInputCMYKProf, Format_CMYK_16, Intent_Absolute_Colorimetric, dcmsFlags);
        stdLabToScreenTrans = colorEngine.createTransform(ScCore->defaultLabProfile, Format_Lab_Dbl, DocDisplayProf, Format_RGB_16, Intent_Absolute_Colorimetric, dcmsFlags);

        bool success = (stdTransRGBMon   && stdTransCMYKMon   && stdProofImg    && stdProofImgCMYK &&
                                        stdTransImg      && stdTransRGB       && stdTransCMYK   && stdProof        &&
                                        stdProofGC       && stdProofCMYK      && stdProofCMYKGC &&
                                        stdLabToRGBTrans && stdLabToCMYKTrans && stdLabToScreenTrans && stdProofLab && stdProofLabGC);
        if (!success)
        {
                CloseCMSProfiles();
                m_docPrefsData.colorPrefs.DCMSset.CMSinUse = false;
                QString message = tr("An error occurred while opening ICC profiles, color management is not enabled." );
                ScMessageBox::warning(m_ScMW, CommonStrings::trWarning, message);
        }
        return true;
}


void ScribusDoc::enableCMS(bool enable)
{
        m_ScMW->setStatusBarInfoText( tr("Adjusting Colors"));
        m_ScMW->mainWindowProgressBar->reset();
        int progressBarCount = PageColors.count() + MasterItems.count() + DocItems.count() + FrameItems.count();
        m_ScMW->mainWindowProgressBar->setMaximum(progressBarCount);
        qApp->setOverrideCursor(QCursor(Qt::WaitCursor));
        bool oldCM = m_docPrefsData.colorPrefs.DCMSset.CMSinUse;
        bool newCM = enable;
        CloseCMSProfiles();
        m_docPrefsData.colorPrefs.DCMSset.CMSinUse = newCM;
        HasCMS       = m_docPrefsData.colorPrefs.DCMSset.CMSinUse;
        BlackPoint   = m_docPrefsData.colorPrefs.DCMSset.BlackPoint;
        SoftProofing = m_docPrefsData.colorPrefs.DCMSset.SoftProofOn;
        Gamut        = m_docPrefsData.colorPrefs.DCMSset.GamutCheck;
        IntentColors = m_docPrefsData.colorPrefs.DCMSset.DefaultIntentColors;
        IntentImages = m_docPrefsData.colorPrefs.DCMSset.DefaultIntentImages;
        if (!m_docPrefsData.colorPrefs.DCMSset.CMSinUse)
        {
                HasCMS = false;
                if (oldCM)
                {
                        m_ScMW->recalcColors();
                        RecalcPictures(&ScCore->InputProfiles, &ScCore->InputProfilesCMYK, m_ScMW->mainWindowProgressBar);
                }
        }
        else if (OpenCMSProfiles(ScCore->InputProfiles, ScCore->InputProfilesCMYK, ScCore->MonitorProfiles, ScCore->PrinterProfiles) )
        {
                HasCMS = true;
                m_docPrefsData.pdfPrefs.SComp = m_docPrefsData.colorPrefs.DCMSset.ComponentsInput2;
                m_docPrefsData.pdfPrefs.SolidProf = m_docPrefsData.colorPrefs.DCMSset.DefaultSolidColorRGBProfile;
                m_docPrefsData.pdfPrefs.ImageProf = m_docPrefsData.colorPrefs.DCMSset.DefaultImageRGBProfile;
                m_docPrefsData.pdfPrefs.PrintProf = m_docPrefsData.colorPrefs.DCMSset.DefaultPrinterProfile;
                m_docPrefsData.pdfPrefs.Intent  = m_docPrefsData.colorPrefs.DCMSset.DefaultIntentColors;
                m_docPrefsData.pdfPrefs.Intent2 = m_docPrefsData.colorPrefs.DCMSset.DefaultIntentImages;
                m_ScMW->recalcColors();
                RecalcPictures(&ScCore->InputProfiles, &ScCore->InputProfilesCMYK, m_ScMW->mainWindowProgressBar);
        }
        else
        {
                SetDefaultCMSParams();
                HasCMS = false;
        }
        m_ScMW->mainWindowProgressBar->setValue(progressBarCount);
        qApp->restoreOverrideCursor();
        m_ScMW->setStatusBarInfoText("");
        m_ScMW->mainWindowProgressBar->reset();
}


void ScribusDoc::getNamedResources(ResourceCollection& lists) const
{
        lists.availableFonts = AllFonts;
        lists.availableColors = const_cast<ColorList*>(& PageColors);

        const QList<PageItem*> * itemlist = & MasterItems;
        while (itemlist != nullptr)
        {
                for (int i=0; i < itemlist->count(); ++i)
                {
                        const PageItem * currItem = const_cast<QList<PageItem*>*>(itemlist)->at(i);
                        if (currItem)
                                currItem->getNamedResources(lists);
                }
                if (itemlist == &MasterItems)
                        itemlist = &DocItems;
                else
                        itemlist = nullptr;
        }
        for (QHash<int, PageItem*>::const_iterator itf = FrameItems.begin(); itf != FrameItems.end(); ++itf)
        {
                PageItem *currItem = itf.value();
                if (currItem)
                        currItem->getNamedResources(lists);
        }
        for (int i = 0; i < m_docParagraphStyles.count(); ++i)
                m_docParagraphStyles[i].getNamedResources(lists);
        for (int i = 0; i < m_docCharStyles.count(); ++i)
                m_docCharStyles[i].getNamedResources(lists);
        for (int i = 0; i < m_docTableStyles.count(); ++i)
                m_docTableStyles[i].getNamedResources(lists);
        for (int i = 0; i < m_docCellStyles.count(); ++i)
                m_docCellStyles[i].getNamedResources(lists);
       
        QHash<QString,ScPattern>::ConstIterator it;
        for (it = docPatterns.begin(); it != docPatterns.end(); ++it)
        {
                ScPattern pa = *it;
                for (int o = 0; o < pa.items.count(); o++)
                {
                        pa.items.at(o)->getNamedResources(lists);
                }
        }
        QHash<QString,VGradient>::ConstIterator itg;
        for (itg = docGradients.begin(); itg != docGradients.end(); ++itg)
        {
                QList<VColorStop*> cstops = itg.value().colorStops();
                for (int cst = 0; cst < itg.value().stops(); ++cst)
                {
                        lists.collectColor(cstops.at(cst)->name);
                }
        }
}

bool ScribusDoc::styleExists(const QString& styleName) const
{
        return m_docParagraphStyles.contains(styleName);
}

bool ScribusDoc::charStyleExists(const QString& styleName) const
{
        return m_docCharStyles.contains(styleName);
}

QList<int> ScribusDoc::getSortedStyleList() const
{
        QList<int> retList;
        for (int i = 0; i < m_docParagraphStyles.count(); ++i)
        {
                if (m_docParagraphStyles[i].parent().isEmpty())
                {
                        if (!retList.contains(i))
                                retList.append(i);
                        continue;
                }

                QList<int> retList2;
                QString name = m_docParagraphStyles[i].name();
                QString par  = m_docParagraphStyles[i].parent();
                retList2.prepend(i);
                while ((!par.isEmpty()) && (par != name))
                {
                        int pp = m_docParagraphStyles.find(par);
                        if ((pp >= 0) && (!retList2.contains(pp)))
                                retList2.prepend(pp);
                        par = (pp >= 0) ? m_docParagraphStyles[pp].parent() : QString();
                }
                for (int r = 0; r < retList2.count(); ++r)
                {
                        if (!retList.contains(retList2[r]))
                                retList.append(retList2[r]);
                }
        }
        return retList;
}

QList<int> ScribusDoc::getSortedCharStyleList() const
{
        QList<int> retList;
        for (int i = 0; i < m_docCharStyles.count(); ++i)
        {
                if (m_docCharStyles[i].parent().isEmpty())
                {
                        if (!retList.contains(i))
                                retList.append(i);
                        continue;
                }

                QList<int> retList2;
                QString name = m_docCharStyles[i].name();
                QString par  = m_docCharStyles[i].parent();
                retList2.prepend(i);
                while ((!par.isEmpty()) && (par != name))
                {
                        int pp = m_docCharStyles.find(par);
                        if ((pp >= 0) && (!retList2.contains(pp)))
                                retList2.prepend(pp);
                        par = (pp >= 0) ? m_docCharStyles[pp].parent() : QString();
                }
                for (int r = 0; r < retList2.count(); ++r)
                {
                        if (!retList.contains(retList2[r]))
                                retList.append(retList2[r]);
                }
        }
        return retList;
}

QList<int> ScribusDoc::getSortedTableStyleList() const
{
        QList<int> retList;
        for (int i = 0; i < m_docTableStyles.count(); ++i)
        {
                if (m_docTableStyles[i].parent().isEmpty())
                {
                        if (!retList.contains(i))
                                retList.append(i);
                        continue;
                }

                QList<int> retList2;
                QString name = m_docTableStyles[i].name();
                QString par  = m_docTableStyles[i].parent();
                retList2.prepend(i);
                while ((!par.isEmpty()) && (par != name))
                {
                        int pp = m_docTableStyles.find(par);
                        if ((pp >= 0) && (!retList2.contains(pp)))
                                retList2.prepend(pp);
                        par = (pp >= 0) ? m_docTableStyles[pp].parent() : QString();
                }
                for (int r = 0; r < retList2.count(); ++r)
                {
                        if (!retList.contains(retList2[r]))
                                retList.append(retList2[r]);
                }
        }
        return retList;
}

QList<int> ScribusDoc::getSortedCellStyleList() const
{
        QList<int> retList;
        for (int i = 0; i < m_docCellStyles.count(); ++i)
        {
                if (m_docCellStyles[i].parent().isEmpty())
                {
                        if (!retList.contains(i))
                                retList.append(i);
                        continue;
                }

                QList<int> retList2;
                QString name = m_docCellStyles[i].name();
                QString par  = m_docCellStyles[i].parent();
                retList2.prepend(i);
                while ((!par.isEmpty()) && (par != name))
                {
                        int pp = m_docCellStyles.find(par);
                        if ((pp >= 0) && (!retList2.contains(pp)))
                                retList2.prepend(pp);
                        par = (pp >= 0) ? m_docCellStyles[pp].parent() : QString();
                }
                for (int r = 0; r < retList2.count(); ++r)
                {
                        if (!retList.contains(retList2[r]))
                                retList.append(retList2[r]);
                }
        }
        return retList;
}

void ScribusDoc::replaceStyles(const QMap<QString,QString>& newNameForOld)
{
        ResourceCollection newNames;
        newNames.mapStyles(newNameForOld);
        replaceNamedResources(newNames);
}

void ScribusDoc::replaceNamedResources(ResourceCollection& newNames)
{
        // replace names in items
        QList<PageItem*> * itemlist = & MasterItems;
        while (itemlist != nullptr)
        {
                for (int i=0; i < itemlist->count(); ++i)
                {
                        PageItem * currItem = itemlist->at(i);
                        if (currItem)
                                currItem->replaceNamedResources(newNames);
                }
                if (itemlist == &MasterItems)
                        itemlist = &DocItems;
                else
                        itemlist = nullptr;
        }
        for (NotesStyle* nStyle : qAsConst(m_docNotesStylesList))
        { //update styles names in notes styles
                if (nStyle == nullptr)
                        continue;
                if (newNames.styles().contains(nStyle->notesParStyle()))
                        nStyle->setNotesParStyle(newNames.styles().value(nStyle->notesParStyle()));
                if (newNames.charStyles().contains(nStyle->marksChStyle()))
                        nStyle->setMarksCharStyle(newNames.charStyles().value(nStyle->marksChStyle()));
        }
        for (auto itf = FrameItems.begin(); itf != FrameItems.end(); ++itf)
        {
                PageItem *currItem = itf.value();
                if (currItem)
                        currItem->replaceNamedResources(newNames);
        }
        // replace names in styles...
        for (int i = m_docParagraphStyles.count() - 1; i >= 0; --i)
        {
                if (newNames.styles().contains(m_docParagraphStyles[i].name()))
                        m_docParagraphStyles.remove(i);
                else
                        m_docParagraphStyles[i].replaceNamedResources(newNames);
        }
        for (int i = m_docCharStyles.count() - 1; i >= 0; --i)
        {
                if (newNames.charStyles().contains(m_docCharStyles[i].name()))
                        m_docCharStyles.remove(i);
                else
                        m_docCharStyles[i].replaceNamedResources(newNames);
        }
        for (int i = m_docTableStyles.count() - 1; i >= 0; --i)
        {
                if (newNames.tableStyles().contains(m_docTableStyles[i].name()))
                        m_docTableStyles.remove(i);
                else
                        m_docTableStyles[i].replaceNamedResources(newNames);
        }
        for (int i = m_docCellStyles.count() - 1; i >= 0; --i)
        {
                if (newNames.cellStyles().contains(m_docCellStyles[i].name()))
                        m_docCellStyles.remove(i);
                else
                        m_docCellStyles[i].replaceNamedResources(newNames);
        }

        QHash<QString,ScPattern>::Iterator it = docPatterns.begin();
        while (it != docPatterns.end())
        {
                if (newNames.patterns().contains(it.key()))
                {
                        it = docPatterns.erase(it);
                        continue;
                }

                ScPattern pa = *it;
                for (int o = 0; o < pa.items.count(); o++)
                {
                        pa.items.at(o)->replaceNamedResources(newNames);
                }
                ++it;
        }

        QHash<QString,VGradient>::Iterator itg = docGradients.begin();
        while (itg != docGradients.end())
        {
                if (newNames.gradients().contains(itg.key()))
                {
                        itg = docGradients.erase(itg);
                        continue;
                }
                       
                QMap<QString,QString>::ConstIterator itc;
                QList<VColorStop*> cstops = itg.value().colorStops();
                for (int cst = 0; cst < itg.value().stops(); ++cst)
                {
                        itc = newNames.colors().find(cstops.at(cst)->name);
                        if (itc != newNames.colors().end())
                        {
                                if (*itc != CommonStrings::None)
                                        cstops.at(cst)->name = *itc;
                        }
                }
                ++itg;
        }
       
        if (newNames.colors().count() > 0 || newNames.fonts().count() > 0)
        {
                m_docCharStyles.invalidate();
                m_docParagraphStyles.invalidate();
                m_docTableStyles.invalidate();
                m_docCellStyles.invalidate();
        }
        else
        {
                if (newNames.charStyles().count() > 0)
                        m_docCharStyles.invalidate();
                if (newNames.styles().count() > 0)
                        m_docParagraphStyles.invalidate();
                if (newNames.tableStyles().count() > 0)
                        m_docTableStyles.invalidate();
                if (newNames.cellStyles().count() > 0)
                        m_docCellStyles.invalidate();
        }
        if (!isLoading() && !(newNames.colors().isEmpty() && newNames.fonts().isEmpty() && newNames.patterns().isEmpty()
                        && newNames.styles().isEmpty() && newNames.charStyles().isEmpty() && newNames.lineStyles().isEmpty()
                        && newNames.tableStyles().isEmpty() && newNames.cellStyles().isEmpty()))
                changed();
}


void ScribusDoc::replaceCharStyles(const QMap<QString,QString>& newNameForOld)
{
        ResourceCollection newNames;
        newNames.mapCharStyles(newNameForOld);
        replaceNamedResources(newNames);
}

void ScribusDoc::replaceTableStyles(const QMap<QString, QString>& newNameForOld)
{
        ResourceCollection newNames;
        newNames.mapTableStyles(newNameForOld);
        replaceNamedResources(newNames);
}

void ScribusDoc::replaceCellStyles(const QMap<QString, QString>& newNameForOld)
{
        ResourceCollection newNames;
        newNames.mapCellStyles(newNameForOld);
        replaceNamedResources(newNames);
}

void ScribusDoc::redefineStyles(const StyleSet<ParagraphStyle>& newStyles, bool removeUnused)
{
        m_docParagraphStyles.redefine(newStyles, false);
        if (removeUnused)
        {
                QMap<QString, QString> deletion;
                QString deflt("");
                for (int i=0; i < m_docParagraphStyles.count(); ++i)
                {
                        const QString& nam(m_docParagraphStyles[i].name());
                        if (newStyles.find(nam) < 0)
                                deletion[nam] = deflt;
                }
                if (deletion.count() > 0)
                        replaceStyles(deletion);
        }
        // repair charstyle context:
        for (int i = 0; i < m_docParagraphStyles.count(); ++i)
        {
                ParagraphStyle& sty(m_docParagraphStyles[i]);
                if (m_docParagraphStyles.isDefault(sty))
                {
                        sty.breakImplicitCharStyleInheritance(true);
                        sty.charStyle().setContext( & m_docCharStyles );
                }
                else {
                        sty.breakImplicitCharStyleInheritance(false);
                }
        }
        m_docParagraphStyles.invalidate();
        if (!isLoading())
        {
                flag_Renumber = true;
                flag_NumUpdateRequest = true;
        }
}

void ScribusDoc::redefineCharStyles(const StyleSet<CharStyle>& newStyles, bool removeUnused)
{
        m_docCharStyles.redefine(newStyles, false);
        if (removeUnused)
        {
                QMap<QString, QString> deletion;
                QString deflt("");
                for (int i = 0; i < m_docCharStyles.count(); ++i)
                {
                        const QString& nam(m_docCharStyles[i].name());
                        if (newStyles.find(nam) < 0)
                        {
                                deletion[nam] = deflt;
                        }
                }
                if (deletion.count() > 0)
                        replaceCharStyles(deletion);
        }
        m_docCharStyles.invalidate();
}

void ScribusDoc::redefineTableStyles(const StyleSet<TableStyle>& newStyles, bool removeUnused)
{
        m_docTableStyles.redefine(newStyles, false);
        if (removeUnused)
        {
                QMap<QString, QString> deletion;
                QString deflt("");
                for (int i = 0; i < m_docTableStyles.count(); ++i)
                {
                        const QString& nam(m_docTableStyles[i].name());
                        if (newStyles.find(nam) < 0)
                        {
                                deletion[nam] = deflt;
                        }
                }
                if (deletion.count() > 0)
                        replaceTableStyles(deletion);
        }
        m_docTableStyles.invalidate();
}

void ScribusDoc::redefineCellStyles(const StyleSet<CellStyle>& newStyles, bool removeUnused)
{
        m_docCellStyles.redefine(newStyles, false);
        if (removeUnused)
        {
                QMap<QString, QString> deletion;
                QString deflt("");
                for (int i = 0; i < m_docCellStyles.count(); ++i)
                {
                        const QString& nam(m_docCellStyles[i].name());
                        if (newStyles.find(nam) < 0)
                        {
                                deletion[nam] = deflt;
                        }
                }
                if (deletion.count() > 0)
                        replaceCellStyles(deletion);
        }
        m_docCellStyles.invalidate();
}

/*
 * Split out from loadStyles in editFormats.cpp so it's callable from anywhere,
 * including plugins.
 * - 2004-09-14 Craig Ringer
 */

// don't like this here. could as well be a static method for reading this stuff into temp., then always use redefineXY() - av
void ScribusDoc::loadStylesFromFile(const QString& fileName)
{
        StyleSet<ParagraphStyle> *wrkStyles     = &m_docParagraphStyles;
        StyleSet<CharStyle> *wrkCharStyles      = &m_docCharStyles;
        QHash<QString, multiLine> *wrkLineStyles = &docLineStyles;
       
        int oldStyles = wrkStyles->count();
        int oldCharStyles = wrkCharStyles->count();
        int oldLineStyles = wrkLineStyles->count();
       
        if (!fileName.isEmpty())
        {
                FileLoader fl(fileName);
                if (fl.testFile() == -1)
                //TODO put in nice user warning
                        return;

                if (!fl.readStyles(this, *wrkStyles))
                {
                        //TODO put in nice user warning
                }

                if (!fl.readCharStyles(this, *wrkCharStyles))
                {
                        //TODO put in nice user warning
                }

                if (!fl.readLineStyles(wrkLineStyles))
                {
                        //TODO put in nice user warning
                }
               
                if ( !isLoading() && ((wrkStyles->count() > oldStyles)
                                    || (wrkCharStyles->count() > oldCharStyles)
                                    || (wrkLineStyles->count() > oldLineStyles) ) )
                        changed();
        }
}

void ScribusDoc::loadStylesFromFile(const QString& fileName, StyleSet<ParagraphStyle> *tempStyles,
                                                      StyleSet<CharStyle> *tempCharStyles,
                                                                                                          QHash<QString, multiLine> *tempLineStyles)
{
        StyleSet<ParagraphStyle> *wrkStyles     = tempStyles;
        StyleSet<CharStyle> *wrkCharStyles      = tempCharStyles;
        QHash<QString, multiLine> *wrkLineStyles = tempLineStyles;
       
        if (fileName.isEmpty())
                return;

        FileLoader fl(fileName);
        if (fl.testFile() == -1)
        //TODO put in nice user warning
                return;

        if (!fl.readStyles(this, *wrkStyles))
        {
                //TODO put in nice user warning
        }

        if (!fl.readCharStyles(this, *wrkCharStyles))
        {
                //TODO put in nice user warning
        }

        if (!fl.readLineStyles(wrkLineStyles))
        {
                //TODO put in nice user warning
        }
               
        // Which are the default styles
        // Sadly StyleSet is not updated at import
        // and it might break something to do so.
        // We need to loop then - pm
                               
        QFileInfo fi(fileName);
        QString importPrefix(tr("Imported ", "Prefix of imported default style"));
        QString importSuffix(" (" +  fi.baseName() + ")");
               
        for (int j(0) ; j < wrkStyles->count() ; ++j)
        {
                if ((*wrkStyles)[j].isDefaultStyle())
                {
                        ParagraphStyle& parDefault((*wrkStyles)[j]);
                        parDefault.setDefaultStyle(false);
                        QMap<QString, QString> namesMap;
                        namesMap[parDefault.name()] = importPrefix + parDefault.name() + importSuffix;
                        for (int i(0) ; i < wrkStyles->count() ; ++i)
                        {
                                if ((*wrkStyles)[i] != parDefault)
                                        namesMap[(*wrkStyles)[i].name()] = (*wrkStyles)[i].name();
                        }
                        wrkStyles->rename(namesMap);
                }
        }
        for (int j(0) ; j < wrkCharStyles->count() ; ++j)
        {
                if ((*wrkCharStyles)[j].isDefaultStyle())
                {
                        CharStyle& charDefault((*wrkCharStyles)[j]);
                        charDefault.setDefaultStyle(false);
                        QMap<QString, QString> namesMap;
                        namesMap[charDefault.name()] = importPrefix + charDefault.name() + importSuffix;
                        for (int i(0) ; i < wrkCharStyles->count() ; ++i)
                        {
                                if ((*wrkCharStyles)[i] != charDefault)
                                        namesMap[(*wrkCharStyles)[i].name()] = (*wrkCharStyles)[i].name();
                        }
                        wrkCharStyles->rename(namesMap);
                }
        }
}


void ScribusDoc::lockGuides(bool isLocked)
{
        if (GuideLock == isLocked)
                return;
        GuideLock = isLocked;
        if (UndoManager::undoEnabled())
        {
                QString name;
                if (isLocked)
                        name = Um::LockGuides;
                else
                        name = Um::UnlockGuides;
                auto* ss = new SimpleState(name, "", Um::ILockGuides);
                ss->set("GUIDE_LOCK", isLocked);
                m_undoManager->action(this, ss);
        }
}

void ScribusDoc::undoRedoBegin()
{
        m_docUpdater->beginUpdate();
        m_Selection->delaySignalsOn();
        ++m_undoRedoOngoing;
}

void ScribusDoc::undoRedoDone()
{
        --m_undoRedoOngoing;
        m_Selection->delaySignalsOff();
        m_docUpdater->endUpdate();
}

void ScribusDoc::restore(UndoState* state, bool isUndo)
{
        auto *ss = dynamic_cast<SimpleState*>(state);
        if (!ss)
                return;

        bool layersUndo = false;
        if (ss->contains("GROUP"))
                restoreGrouping(ss, isUndo);
        else if (ss->contains("UNGROUP"))
                restoreGrouping(ss, !isUndo);
        else if (ss->contains("GUIDE_LOCK"))
                restoreGuideLock(ss, isUndo);
        else if (ss->contains("UP_LAYER"))
        {
                if (isUndo)
                        lowerLayer(ss->getInt("ACTIVE"));
                else
                        raiseLayer(ss->getInt("ACTIVE"));
                layersUndo = true;
        }
        else if (ss->contains("DOWN_LAYER"))
        {
                if (isUndo)
                        raiseLayer(ss->getInt("ACTIVE"));
                else
                        lowerLayer(ss->getInt("ACTIVE"));
                layersUndo = true;
        }
        else if (ss->contains("PRINT_LAYER"))
        {
                bool print = ss->getBool("PRINT");
                setLayerPrintable(ss->getInt("ACTIVE"), isUndo ? !print : print);
                layersUndo = true;
        }
        else if (ss->contains("LAYER_FLOW"))
        {
                bool flow = ss->getBool("FLOW");
                setLayerFlow(ss->getInt("ACTIVE"), isUndo ? !flow : flow);
                layersUndo = true;
        }
        else if (ss->contains("LAYER_LOCK"))
        {
                bool lock = ss->getBool("LOCK");
                setLayerLocked(ss->getInt("ACTIVE"), isUndo ? !lock : lock);
                layersUndo = true;
        }
        else if (ss->contains("LAYER_TRANSPARENCY"))
        {
                double old_trans = ss->getDouble("OLD_TRANS");
                double new_trans = ss->getDouble("NEW_TRANS");
                setLayerTransparency(ss->getInt("ACTIVE"), isUndo ? old_trans : new_trans);
                layersUndo = true;
        }
        else if (ss->contains("LAYER_BLENDMODE"))
        {
                int old_blend = ss->getInt("OLD_BLENDMODE");
                int new_blend = ss->getInt("NEW_BLENDMODE");
                setLayerBlendMode(ss->getInt("ACTIVE"), isUndo ? old_blend : new_blend);
                layersUndo = true;
        }
        else if (ss->contains("ADD_LAYER"))
        {
                if (isUndo)
                        deleteLayer(ss->getInt("LAYER_NR"), false);
                else
                {
                        int layerID = addLayer(ss->get("NAME"), false);
                        int newLayerID = ss->getInt("LAYER_NR");
                        bool renumberedOk=renumberLayer(layerID, newLayerID);
                        Q_ASSERT(renumberedOk);
                }
                layersUndo = true;
        }
        else if (ss->contains("REMOVE_LAYER"))
        {
                if (isUndo)
                {
                        int layerID = addLayer(ss->get("NAME"), false);
                        int newLayerID = ss->getInt("LAYER_NR");
                        bool renumberedOk=renumberLayer(layerID, newLayerID);
                        Q_ASSERT(renumberedOk);
                        layerID = newLayerID;
                        //Layer is at the top now, lower it until it reaches the old level
                        int level = ss->getInt("LEVEL");
                        while (layerLevelFromID(layerID)!=level)
                                lowerLayer(layerID);
                }
                else
                        deleteLayer(ss->getInt("LAYER_NR"), ss->getBool("DELETE"));
                layersUndo = true;
        }
        else if (ss->contains("CHANGE_NAME"))
        {
                QString name = ss->get("OLD_NAME");
                if (!isUndo)
                        name = ss->get("NEW_NAME");
                changeLayerName(ss->getInt("ACTIVE"), name);
                layersUndo = true;
        }
        else if (ss->contains("MASTERPAGE_ADD"))
                restoreAddMasterPage(ss, isUndo);
        else if (ss->contains("MASTERPAGE_RENAME"))
                restoreMasterPageRenaming(ss, isUndo);
        else if (ss->contains("OLD_MASTERPAGE"))
                restoreMasterPageApplying(ss, isUndo);
        else if (ss->contains("PAGE_COPY"))
                restoreCopyPage(ss, isUndo);
        else if (ss->contains("PAGE_MOVE"))
                restoreMovePage(ss, isUndo);
        else if (ss->contains("PAGE_SWAP"))
                restoreSwapPage(ss, isUndo);
        else if (ss->contains("LEVEL_DOWN"))
                restoreLevelDown(ss,isUndo);
        else if (ss->contains("LEVEL_UP"))
                restoreLevelDown(ss,!isUndo);
        else if (ss->contains("LEVEL_BOTTOM"))
                restoreLevelBottom(ss,isUndo);
        else if (ss->contains("LEVEL_TOP"))
                restoreLevelBottom(ss,!isUndo);
        else if (ss->contains("PAGE_CHANGEPROPS"))
                restoreChangePageProperties(ss,isUndo);
        else if (ss->contains("DELETE_FRAMETEXT"))
        {
                PageItem * nF = getItemFromName(ss->get("noteframeName"));
                Q_ASSERT(nF != nullptr);
                nF->asNoteFrame()->restoreDeleteNoteText(ss, isUndo);
        }
        else if (ss->contains("DELETE_FRAMEPARA"))
        {
                PageItem * nF = getItemFromName(ss->get("noteframeName"));
                Q_ASSERT(nF != nullptr);
                nF->asNoteFrame()->restoreDeleteNoteParagraph(ss, isUndo);
        }
        else if (ss->contains("INSERT_FRAMETEXT"))
        {
                PageItem * nF = getItemFromName(ss->get("noteframeName"));
                Q_ASSERT(nF != nullptr);
                nF->asNoteFrame()->restoreInsertNoteText(ss,isUndo);
        }
        else if (ss->contains("INSERT_FRAMEPARA"))
        {
                PageItem * nF = getItemFromName(ss->get("noteframeName"));
                Q_ASSERT(nF != nullptr);
                nF->asNoteFrame()->restoreInsertNoteParagraph(ss,isUndo);
        }
        else if (ss->contains("NSTYLE"))
                restoreNoteStyle(ss, isUndo);
        else if (ss->contains("DELETE_NOTE"))
                restoreDeleteNote(state, isUndo);
        else if (ss->contains("MARK"))
                restoreMarks(state, isUndo);

        if (layersUndo)
        {
                if (ScCore->usingGUI())
                {
                        if (ss->contains("ACTIVE"))
                                scMW()->layerPalette->setActiveLayer(layerLevelFromID(ss->getInt("ACTIVE")),0);
                        m_ScMW->changeLayer(ss->getInt("ACTIVE"));
                        m_ScMW->layerPalette->rebuildList();
                        if (m_ScMW->outlinePalette->isVisible())
                                m_ScMW->outlinePalette->BuildTree();
                }
        }
}

void ScribusDoc::restoreLevelDown(SimpleState* ss, bool isUndo)
{
        ScItemState<QList<QPointer<PageItem> > > *is = dynamic_cast<ScItemState<QList<QPointer<PageItem> > > *>(ss);
        if (!is)
                return;
        QList<QPointer<PageItem> > listItem = is->getItem();
        m_Selection->clear();
        for (int i = 0; i<listItem.size();i++)
                m_Selection->addItem(listItem.at(i));
        if (isUndo)
                itemSelection_RaiseItem();
        else
                itemSelection_LowerItem();
}

void ScribusDoc::restoreLevelBottom(SimpleState* ss, bool isUndo)
{
        ScItemState<QList<QPointer<PageItem> > > *is = dynamic_cast<ScItemState<QList<QPointer<PageItem> > > *>(ss);
        if (!is)
                return;
        QList<QPointer<PageItem> > listItem = is->getItem();
        m_Selection->clear();
        for (int i = 0; i<listItem.size();i++)
                m_Selection->addItem(listItem.at(i));
        if (isUndo)
                bringItemSelectionToFront();
        else
                sendItemSelectionToBack();
}

void ScribusDoc::restoreGuideLock(SimpleState* ss, bool isUndo)
{
        if (isUndo)
                GuideLock = !ss->getBool("GUIDE_LOCK");
        else
                GuideLock = ss->getBool("GUIDE_LOCK");
}

void ScribusDoc::restoreAddMasterPage(SimpleState* ss, bool isUndo)
{
        QString pageName = ss->get("MASTERPAGE_NAME");
        int pageNr = ss->getInt("MASTERPAGE_NBR");

        bool oldMPMode  = masterPageMode();
        ScPage* oldPage = currentPage();

        setMasterPageMode(true);
        if (isUndo)
        {
                auto *duo = new DummyUndoObject();
                uint did = static_cast<uint>(duo->getUId());
                m_undoManager->replaceObject(Pages->at(MasterNames[pageName])->getUId(), duo);
                ss->set("DUMMY_ID", did);

                scMW()->deletePage2(MasterNames[pageName]);
                rebuildMasterNames();
        }
        else
        {
                ScPage* Mpage = addMasterPage(pageNr, pageName);
                setCurrentPage(Mpage);
                UndoObject *tmp = m_undoManager->replaceObject(
                                        ss->getUInt("DUMMY_ID"), Pages->at(MasterNames[pageName]));
                delete tmp;
        }
        setMasterPageMode(oldMPMode);
        if (!oldMPMode)
                setCurrentPage(oldPage);
        scMW()->pagePalette->updateMasterPageList();
        m_View->reformPages();
}

void ScribusDoc::restoreChangePageProperties(SimpleState* state, bool isUndo)
{
        bool oldMPMode  = masterPageMode();
        ScPage* oldPage = currentPage();

        setMasterPageMode(state->getBool("MASTER_PAGE_MODE"));
        setCurrentPage(Pages->at(state->getInt("PAGE_NUM")));
        if (isUndo)
        {
//              qDebug()<<"undo setting orientation to"<<state->getInt("OLD_PAGE_ORIENTATION");
                changePageProperties(state->getDouble("OLD_PAGE_INITIALTOP"), state->getDouble("OLD_PAGE_INITIALBOTTOM"),
                                state->getDouble("OLD_PAGE_INITIALLEFT"), state->getDouble("OLD_PAGE_INITIALRIGHT"),
                                state->getDouble("OLD_PAGE_INITIALHEIGHT"), state->getDouble("OLD_PAGE_INITIALWIDTH"),
                                state->getDouble("OLD_PAGE_HEIGHT"), state->getDouble("OLD_PAGE_WIDTH"), state->getInt("OLD_PAGE_ORIENTATION"),
                                state->get("OLD_PAGE_SIZE"), state->getInt("OLD_PAGE_MARGINPRESET"), state->getBool("OLD_PAGE_MOVEOBJECTS"), state->getInt("PAGE_NUM"), state->getInt("OLD_PAGE_TYPE"));
        }
        else
        {
//              qDebug()<<"redo setting orientation to"<<state->getInt("NEW_PAGE_ORIENTATION");
                changePageProperties(state->getDouble("NEW_PAGE_INITIALTOP"), state->getDouble("NEW_PAGE_INITIALBOTTOM"),
                                state->getDouble("NEW_PAGE_INITIALLEFT"), state->getDouble("NEW_PAGE_INITIALRIGHT"),
                                state->getDouble("NEW_PAGE_INITIALHEIGHT"), state->getDouble("NEW_PAGE_INITIALWIDTH"),
                                state->getDouble("NEW_PAGE_HEIGHT"), state->getDouble("NEW_PAGE_WIDTH"), state->getInt("NEW_PAGE_ORIENTATION"),
                                state->get("NEW_PAGE_SIZE"), state->getInt("NEW_PAGE_MARGINPRESET"), state->getBool("OLD_PAGE_MOVEOBJECTS"), state->getInt("PAGE_NUM"), state->getInt("NEW_PAGE_TYPE"));
        }
        setMasterPageMode(oldMPMode);
        setCurrentPage(oldPage);
}

void ScribusDoc::restoreGrouping(SimpleState* ss, bool isUndo)
{
        auto* is = dynamic_cast<ScItemState<QList<QPointer<PageItem> > >*>(ss);
        if (!is)
                qFatal("ScribusDoc::restoreGrouping: dynamic cast failed");

        QList<QPointer<PageItem> > select = is->getItem();
        m_Selection->delaySignalsOn();
        for (int i = 0; i < select.count(); ++i)
                m_Selection->removeItem(select.at(i));
        Selection tempSelect(this, false);
        double x, y, w, h;
        if (isUndo)
        {
                tempSelect.addItem(select.first()->Parent);
                tempSelect.getGroupRect(&x, &y, &w, &h);
                itemSelection_UnGroupObjects(&tempSelect);
        }
        else
        {
                for (int i = 0; i < select.size() - 1; ++i)
                        tempSelect.addItem(select.at(i));
                tempSelect.getGroupRect(&x, &y, &w, &h);
                PageItem_Group* oldGroupItem = select.last()->asGroupFrame();
                PageItem* newGroupItem = itemSelection_GroupObjects(false, false, &tempSelect, oldGroupItem);
                select.removeLast();
                select.append(newGroupItem);
                is->setItem(select);
        }
        QRectF rect(x, y , w, h);
        regionsChanged()->update(rect.adjusted(-10, -10, 20, 20));
        m_Selection->delaySignalsOff();
}

void ScribusDoc::restoreMarks(UndoState* state, bool isUndo)
{
        auto *is = dynamic_cast<ScItemsState*>(state);
        if (!is)
                return;

        Mark* mrk = getMark(is->get("label"), (MarkType) is->getInt("type"));
        if (mrk == nullptr && is->contains("labelOLD"))
                mrk = getMark(is->get("labelOLD"), (MarkType) is->getInt("type"));
        int pos = is->getInt("at");

        bool isAutoNoteFrame = false;
        PageItem* currItem = nullptr;
        if (is->contains("noteframeName"))
        {
                currItem = getItemFromName(is->get("noteframeName"));
                if (currItem != nullptr)
                        isAutoNoteFrame = currItem->asNoteFrame()->isAutoFrame();
        }
        else
                currItem = (PageItem*) is->getItem("inItem");
       
        QString markAction = is->get("MARK");
        if (isUndo)
        {
                if (markAction == "new")
                {
                        Q_ASSERT(mrk != nullptr);
                        if (mrk->isNoteType())
                        {
                                TextNote* note = mrk->getNotePtr();
                                NotesStyle* nStyle = note->notesStyle();
                                if (note->isEndNote())
                                        flag_updateEndNotes = true;
                                deleteNote(note);
                                updateNotesNums(nStyle);
                        }
                        else
                                eraseMark(mrk, true, currItem, true);
                }
                else if (markAction == "replace")
                {
                        Q_ASSERT(pos >= 0);
                        Q_ASSERT(currItem != nullptr);
                        Q_ASSERT(mrk != nullptr);
                        Mark* mrk = getMark(is->get("label"), (MarkType) is->getInt("type"));
                        currItem->itemText.replaceMark(pos, mrk);
                        if (is->contains("strtxtOLD"))
                        {
                                mrk->setString(is->get("strtxtOLD"));
                                invalidateVariableTextFrames(mrk, false);
                        }
                        if (is->contains("labelOLD"))
                                mrk->label = is->get("labelOLD");
                }
                else if (markAction == "edit")
                {
                        Q_ASSERT(mrk != nullptr);
                        if (is->contains("labelOLD"))
                                mrk->label = is->get("labelOLD");
                        if (is->contains("strtxtOLD"))
                        {
                                mrk->setString(is->get("strtxtOLD"));
                                invalidateVariableTextFrames(mrk, false);
                        }
                        if (is->contains("dNameOLD"))
                                mrk->setDestMark(is->get("dNameOLD"), (MarkType) is->getInt("dTypeOLD"));
                        if (is->getItem("itemPtrOLD") != nullptr)
                                mrk->setItemPtr((PageItem*) is->getItem("itemPtrOLD"));
                }
                else if (markAction == "insert_existing")
                {
                        Q_ASSERT(pos >= 0);
                        Q_ASSERT(currItem != nullptr);
                        Q_ASSERT(mrk != nullptr);
                        currItem->itemText.removeChars(pos, 1);
                        if (is->contains("strOLD"))
                        {
                                mrk->setString(is->get("strOLD"));
                                invalidateVariableTextFrames(mrk, false);
                        }
                        if (is->contains("labelOLD"))
                                mrk->label = is->get("labelOLD");
                }
                else if (markAction == "delete")
                {
                        mrk = newMark();
                        mrk->label = is->get("label");
                        mrk->setType((MarkType) is->getInt("type"));
                        Q_ASSERT(pos >= 0);
                        Q_ASSERT(currItem != nullptr);
                        currItem->itemText.insertMark(mrk, pos);
                        if (is->contains("strtxt"))
                        {
                                mrk->setString(is->get("strtxt"));
                                invalidateVariableTextFrames(mrk, false);
                        }
                        if (is->contains("dName"))
                                mrk->setDestMark(is->get("dName"), (MarkType) is->getInt("dType"));
                        if (is->getItem("itemPtr") != nullptr)
                                mrk->setItemPtr((PageItem*) is->getItem("itemPtr"));
                }
                else if (markAction == "eraseFromText") ////for non-unique marks
                {
                        Q_ASSERT(pos >= 0);
                        Q_ASSERT(mrk != nullptr);
                        Q_ASSERT(currItem != nullptr);
                        currItem->itemText.insertMark(mrk, pos);
                        if (is->contains("strNew"))
                        {
                                mrk->setString(is->get("strNEW"));
                                invalidateVariableTextFrames(mrk, false);
                        }
                }
                else if (markAction == "delNonUnique")
                {
                        //used if deleting non-unique marks by MarksManager
                        mrk = newMark();
                        mrk->label = is->get("label");
                        mrk->setType((MarkType) is->getInt("type"));
                        mrk->setString(is->get("strtxt"));
                        for (int i=0; i < is->insertItemPos.count(); ++i)
                        {
                                PageItem* item = (PageItem*) is->insertItemPos[i].first;
                                item->itemText.insertMark(mrk, is->insertItemPos[i].second);
                                item->invalid = true;
                        }
                }
                else
                {
                        Q_ASSERT(false);
                        qDebug() << "MARK undo - unhandled " << is->get("MARK");
                }
        }
        else  //REDO
        {
                if (markAction == "new")
                {
                        if (currItem == nullptr)
                        {
                                qDebug() << "Wrong inItem in undo step for mark";
                                return;
                        }
                        mrk = newMark();
                        mrk->label = is->get("label");
                        mrk->setType((MarkType) is->getInt("type"));
                        Q_ASSERT(currItem != nullptr);
                        Q_ASSERT(pos >= 0);
                        currItem->itemText.insertMark(mrk, pos);
                        if (is->contains("strtxt"))
                                mrk->setString(is->get("strtxt"));
                        if (is->contains("dName"))
                                mrk->setDestMark(is->get("dName"), (MarkType) is->getInt("dType"));
                        if (is->getItem("itemPtr") != nullptr)
                                mrk->setItemPtr((PageItem*) is->getItem("itemPtr"));
                        if (mrk->isType(MARKNoteMasterType))
                        {
                                NotesStyle* nStyle = getNotesStyle(is->get("nStyle"));
                                TextNote* note = newNote(nStyle);
                                mrk->setNotePtr(note);
                                note->setMasterMark(mrk);
                                if (nStyle->isEndNotes())
                                        flag_updateEndNotes = true;
                                updateNotesNums(nStyle);
                        }
                }
                else if (markAction == "replace")
                {
                        Q_ASSERT(currItem != nullptr);
                        Q_ASSERT(pos >= 0);
                        currItem->itemText.replaceMark(pos, getMark(is->get("label"), (MarkType) is->getInt("type")));
                        if (is->contains("strtxtNEW"))
                        {
                                mrk->setString(is->get("strtxtNEW"));
                                invalidateVariableTextFrames(mrk, false);
                        }
                        if (is->contains("labelNEW"))
                                mrk->label = is->get("labelNEW");
                }
                else if (markAction == "edit")
                {
                        if (is->contains("labelNEW"))
                                mrk->label = is->get("labelNEW");
                        if (is->contains("strtxtNEW"))
                        {
                                mrk->setString(is->get("strtxtNEW"));
                                invalidateVariableTextFrames(mrk, false);
                        }
                        if (is->contains("dNameNEW"))
                                mrk->setDestMark(is->get("dNameNEW"), (MarkType) is->getInt("dTypeNEW"));
                        if (is->getItem("itemPtrNEW") != nullptr)
                                mrk->setItemPtr((PageItem*) is->getItem("itemPtrNEW"));
                }
                else if (markAction == "insert_existing")
                {
                        Q_ASSERT(currItem != nullptr);
                        Q_ASSERT(pos >= 0);
                        currItem->itemText.insertMark(mrk, pos);
                        if (is->contains("strNew"))
                        {
                                mrk->setString(is->get("strNEW"));
                                invalidateVariableTextFrames(mrk, false);
                        }
                        if (is->contains("labelNEW"))
                                mrk->label = is->get("labelNEW");
                }
                else if (markAction == "eraseFromText") //for non-unique marks
                {
                        Q_ASSERT(currItem != nullptr);
                        Q_ASSERT(pos >= 0);
                        currItem->itemText.removeChars(pos, 1);
                }
                else if (markAction == "delete")
                {
                        if (!mrk->isUnique())
                        {
                                Q_ASSERT(currItem != nullptr);
                                Q_ASSERT(pos >= 0);
                                currItem->itemText.removeChars(pos, 1);
                        }
                        else
                        {
                                if (mrk->isType(MARKNoteMasterType))
                                {
                                        TextNote* note = mrk->getNotePtr();
                                        NotesStyle* nStyle = note->notesStyle();
                                        if (note->isEndNote())
                                                flag_updateEndNotes = true;
                                        deleteNote(note);
                                        updateNotesNums(nStyle);
                                }
                                else
                                        eraseMark(mrk, true);
                        }
                }
                else if (markAction == "delNonUnique")
                {
                        //used if deleting non-unique marks by MarksManager
                        eraseMark(mrk, true, nullptr, true);
                }
                else
                {
                        qDebug() << "MARK redo - unhandled " << is->get("MARK");
                }
        }

        scMW()->emitUpdateRequest(reqMarksUpdate);
        if (currItem != nullptr && !isAutoNoteFrame)
        {
                currItem->invalidateLayout();
                currItem->updateLayout();
        }
}

void ScribusDoc::restoreNoteStyle(SimpleState* ss, bool isUndo)
{
        NotesStyle* noteStyle = nullptr;
        if ((ss->get("NSTYLE") == "new" && isUndo) || (ss->get("NSTYLE") == "delete" && !isUndo))
                deleteNotesStyle(ss->get("name"));
        else if ((ss->get("NSTYLE") == "new" && !isUndo) || (ss->get("NSTYLE") == "delete" && isUndo))
        {
                noteStyle = new NotesStyle();
                noteStyle->setName(ss->get("name"));
                noteStyle->setStart(ss->getInt("start"));
                noteStyle->setEndNotes(ss->getBool("endNotes"));
                noteStyle->setType((NumFormat) ss->getInt("numFormat"));
                noteStyle->setRange((NumerationRange) ss->getInt("range"));
                noteStyle->setPrefix(ss->get("prefix"));
                noteStyle->setSuffix(ss->get("suffix"));
                noteStyle->setAutoNotesHeight(ss->getBool("autoH"));
                noteStyle->setAutoNotesWidth(ss->getBool("autoW"));
                noteStyle->setAutoWeldNotesFrames(ss->getBool("autoWeld"));
                noteStyle->setAutoRemoveEmptyNotesFrames(ss->getBool("autoRemove"));
                noteStyle->setSuperscriptInMaster(ss->getBool("superMaster"));
                noteStyle->setSuperscriptInNote(ss->getBool("superNote"));
                noteStyle->setMarksCharStyle(ss->get("marksChStyle"));
                noteStyle->setNotesParStyle(ss->get("notesParStyle"));
                m_docNotesStylesList.append(noteStyle);
                scMW()->emitUpdateRequest(reqMarksUpdate);
        }
        else if (ss->get("NSTYLE") == "edit")
        {
                if (isUndo)
                        noteStyle = getNotesStyle(ss->get("NEWname"));
                else
                        noteStyle = getNotesStyle(ss->get("name"));
                Q_ASSERT(noteStyle != nullptr);
                //check if Notes Style change form footnotes to endnotes or range of numeration was changed
                //if use delete all notes frames with current style
                bool delNF = false;
                if (ss->getBool("NEWendNotes") != ss->getBool("endNotes")
                        || ((isUndo && (ss->getBool("endNotes") && (NumerationRange) ss->getInt("range") != (NumerationRange) ss->getInt("NEWrange")))
                        || (!isUndo && (ss->getBool("NEWendNotes") && ((NumerationRange) ss->getInt("NEWrange") != (NumerationRange) ss->getInt("range"))))))
                                delNF = true;
                if (delNF)
                {
                        auto noteFrameList = listNotesFrames(noteStyle);
                        for (PageItem_NoteFrame* noteFrame : qAsConst(noteFrameList))
                                delNoteFrame(noteFrame, false);
                        flag_updateEndNotes = noteStyle->isEndNotes();
                }
                if (isUndo)
                {
                        noteStyle->setName(ss->get("name"));
                        noteStyle->setStart(ss->getInt("start"));
                        noteStyle->setRange((NumerationRange) ss->getInt("range"));
                        noteStyle->setEndNotes(ss->getBool("endNotes"));
                        noteStyle->setType((NumFormat) ss->getInt("numFormat"));
                        noteStyle->setPrefix(ss->get("prefix"));
                        noteStyle->setSuffix(ss->get("suffix"));
                        noteStyle->setAutoNotesHeight(ss->getBool("autoH"));
                        noteStyle->setAutoNotesWidth(ss->getBool("autoW"));
                        noteStyle->setAutoWeldNotesFrames(ss->getBool("autoWeld"));
                        noteStyle->setAutoRemoveEmptyNotesFrames(ss->getBool("autoRemove"));
                        noteStyle->setSuperscriptInMaster(ss->getBool("superMaster"));
                        noteStyle->setSuperscriptInNote(ss->getBool("superNote"));
                        noteStyle->setMarksCharStyle(ss->get("marksChStyle"));
                        noteStyle->setNotesParStyle(ss->get("notesParStyle"));
                }
                else
                {
                        noteStyle->setName(ss->get("NEWname"));
                        noteStyle->setStart(ss->getInt("NEWstart"));
                        noteStyle->setRange((NumerationRange) ss->getInt("NEWrange"));
                        noteStyle->setEndNotes(ss->getBool("NEWendNotes"));
                        noteStyle->setType((NumFormat) ss->getInt("NEWnumFormat"));
                        noteStyle->setPrefix(ss->get("NEWprefix"));
                        noteStyle->setSuffix(ss->get("NEWsuffix"));
                        noteStyle->setAutoNotesHeight(ss->getBool("NEWautoH"));
                        noteStyle->setAutoNotesWidth(ss->getBool("NEWautoW"));
                        noteStyle->setAutoWeldNotesFrames(ss->getBool("NEWautoWeld"));
                        noteStyle->setAutoRemoveEmptyNotesFrames(ss->getBool("NEWautoRemove"));
                        noteStyle->setSuperscriptInMaster(ss->getBool("NEWsuperMaster"));
                        noteStyle->setSuperscriptInNote(ss->getBool("NEWsuperNote"));
                        noteStyle->setMarksCharStyle(ss->get("NEWmarksChStyle"));
                        noteStyle->setNotesParStyle(ss->get("NEWnotesParStyle"));
                }
                setNotesChanged(true);
                if ((ss->get("marksChStyle") != ss->get("NEWmarksChStyle"))
                        || (ss->getBool("superMaster") != ss->getBool("NEWsuperMaster")))
                        invalidateMasterFrames(noteStyle);
                updateNotesNums(noteStyle);
                updateNotesFramesSettings(noteStyle);
                if (flag_updateEndNotes)
                        updateEndnotesFrames(noteStyle, true);
                updateNotesFramesStyles(noteStyle);
                if (notesChanged())
                {
                        flag_updateMarksLabels = true;
                        changed();
                        regionsChanged()->update(QRectF());
                }
        }
        if (noteStyle != nullptr)
                scMW()->nsEditor->setNotesStyle(noteStyle);
        else
                scMW()->nsEditor->updateNSList();
}

void ScribusDoc::restoreDeleteNote(UndoState* state, bool isUndo)
{
        auto *is = dynamic_cast<ScItemsState*>(state);
        if (!is)
                return;

        NotesStyle* nStyle = getNotesStyle(is->get("nStyle"));
        PageItem* master = nullptr;
        if (is->contains("noteframeName"))
                master = getItemFromName(is->get("noteframeName"));
        else
                master = (PageItem*) is->getItem("inItem");

        if (isUndo)
        {
                TextNote* note = newNote(nStyle);
                Mark* mrk = newMark();
                mrk->setType(MARKNoteMasterType);
                mrk->setNotePtr(note);
                note->setMasterMark(mrk);
                note->setSaxedText(is->get("noteTXT"));
                master->itemText.insertMark(mrk, is->getInt("at"));
                master->invalid = true;
                if (!nStyle->isAutoRemoveEmptyNotesFrames())
                {
                        PageItem_NoteFrame* nF = (PageItem_NoteFrame*) is->getItem("noteframe");
                        Q_ASSERT(nF != nullptr);
                        master->asTextFrame()->setNoteFrame(nF);
                }
                setNotesChanged(true);
                if (note->isEndNote())
                        flag_updateEndNotes = true;
        }
        else
        {
                TextNote* note = master->itemText.mark(is->getInt("at"))->getNotePtr();
                if (note->isEndNote())
                        flag_updateEndNotes = true;
                deleteNote(note);
        }
        master->invalidateLayout();
        master->updateLayout();
}

void ScribusDoc::setModified(bool isModified)
{
        if (m_modified != isModified)
        {
                m_modified = isModified;
                update();
        }
}

bool ScribusDoc::isModified() const
{
        return m_modified;
}

bool ScribusDoc::isUndoRedoOngoing() const
{
        return (m_undoRedoOngoing != 0);
}

/** sets page properties */
void ScribusDoc::setPage(double w, double h, double t, double l, double r, double b, double sp, double ab, bool atf, int fp)
{
        m_docPrefsData.docSetupPrefs.pageWidth = w;
        m_docPrefsData.docSetupPrefs.pageHeight = h;
        m_docPrefsData.docSetupPrefs.margins.set(t, l, b ,r);
        PageSp = sp;
        PageSpa = ab;
        m_docPrefsData.docSetupPrefs.pagePositioning = fp;
        m_automaticTextFrames = atf;
}



bool ScribusDoc::AddFont(const QString& name, int fsize)
{
        if (UsedFonts.contains(name))
                return true;

        if (! AllFonts->contains(name) || name == "" )
                return false;

        UsedFonts[name] = fsize;
        (*AllFonts)[name].increaseUsage();

        return true;
}


QStringList ScribusDoc::getItemAttributeNames() const
{
        QStringList nameList;

        auto itemAttrs = itemAttributes();
        for (ObjAttrVector::Iterator it = itemAttrs.begin(); it!= itemAttrs.end(); ++it)
                nameList.append((*it).name);
        return nameList;
}


void ScribusDoc::addSymbols()
{
        symReturn.resize(0);
        symReturn.addQuadPoint(1.98438, 9.14062, 1.98438, 9.14062, 1.98438, 4.03125, 1.98438, 4.03125);
        symReturn.addQuadPoint(1.98438, 4.03125, 1.98438, 4.03125, 0.546875, 3.45312, 1.09375, 4);
        symReturn.addQuadPoint(0.546875, 3.45312, 0.546875, 3.45312, 0, 2.0625, 0, 2.92188);
        symReturn.addQuadPoint(0, 2.0625, 0, 2.0625, 0.65625, 0.5, 0, 1.04688);
        symReturn.addQuadPoint(0.65625, 0.5, 0.65625, 0.5, 2.3125, 0, 1.28125, 0);
        symReturn.addQuadPoint(2.3125, 0, 2.3125, 0, 5.40625, 0, 5.40625, 0);
        symReturn.addQuadPoint(5.40625, 0, 5.40625, 0, 5.40625, 0.84375, 5.40625, 0.84375);
        symReturn.addQuadPoint(5.40625, 0.84375, 5.40625, 0.84375, 4.70312, 0.84375, 4.70312, 0.84375);
        symReturn.addQuadPoint(4.70312, 0.84375, 4.70312, 0.84375, 4.70312, 9.14062, 4.70312, 9.14062);
        symReturn.addQuadPoint(4.70312, 9.14062, 4.70312, 9.14062, 3.875, 9.14062, 3.875, 9.14062);
        symReturn.addQuadPoint(3.875, 9.14062, 3.875, 9.14062, 3.875, 0.84375, 3.875, 0.84375);
        symReturn.addQuadPoint(3.875, 0.84375, 3.875, 0.84375, 2.78125, 0.84375, 2.78125, 0.84375);
        symReturn.addQuadPoint(2.78125, 0.84375, 2.78125, 0.84375, 2.78125, 9.14062, 2.78125, 9.14062);
        symReturn.addQuadPoint(2.78125, 9.14062, 2.78125, 9.14062, 1.98438, 9.14062, 1.98438, 9.14062);
        symNewLine.resize(0);
        symNewLine.addQuadPoint(6.51562, 2.625, 6.51562, 2.625, 0.90625, 2.64062, 0.90625, 2.64062);
        symNewLine.addQuadPoint(0.90625, 2.64062, 0.90625, 2.64062, 1.4375, 1.92188, 1.26562, 2.1875);
        symNewLine.addQuadPoint(1.4375, 1.92188, 1.4375, 1.92188, 1.76562, 1.14062, 1.75, 1.42188);
        symNewLine.addQuadPoint(1.76562, 1.14062, 1.76562, 1.14062, 1.60938, 1.03125, 1.60938, 1.03125);
        symNewLine.addQuadPoint(1.60938, 1.03125, 1.60938, 1.03125, 0.90625, 1.92188, 0.90625, 1.92188);
        symNewLine.addQuadPoint(0.90625, 1.92188, 0.90625, 1.92188, 0, 2.90625, 0.578125, 2.23438);
        symNewLine.addQuadPoint(0, 2.90625, 0, 2.90625, 0.75, 3.875, 0.75, 3.875);
        symNewLine.addQuadPoint(0.75, 3.875, 0.75, 3.875, 1.57812, 4.78125, 1.1875, 4.40625);
        symNewLine.addQuadPoint(1.57812, 4.78125, 1.57812, 4.78125, 1.65625, 4.79688, 1.65625, 4.79688);
        symNewLine.addQuadPoint(1.65625, 4.79688, 1.65625, 4.79688, 1.76562, 4.65625, 1.76562, 4.65625);
        symNewLine.addQuadPoint(1.76562, 4.65625, 1.76562, 4.65625, 0.90625, 3.17188, 1.73438, 4.34375);
        symNewLine.addQuadPoint(0.90625, 3.17188, 0.90625, 3.17188, 0.96875, 3.125, 0.96875, 3.125);
        symNewLine.addQuadPoint(0.96875, 3.125, 0.96875, 3.125, 6.75, 3.125, 6.75, 3.125);
        symNewLine.addQuadPoint(6.75, 3.125, 6.75, 3.125, 6.51562, 2.625, 6.51562, 2.625);
        symNewLine.addQuadPoint(6.51562, 2.625, 6.51562, 2.625, 6.51562, 2.625, 6.51562, 2.625);
        symNewLine.setMarker();
        symNewLine.addQuadPoint(6.875, 0, 6.875, 0, 6.51562, 0, 6.51562, 0);
        symNewLine.addQuadPoint(6.51562, 0, 6.51562, 0, 6.51562, 2.84375, 6.51562, 2.84375);
        symNewLine.addQuadPoint(6.51562, 2.84375, 6.51562, 2.84375, 6.75, 3.125, 6.51562, 3.125);
        symNewLine.addQuadPoint(6.75, 3.125, 6.75, 3.125, 6.85938, 3.0625, 6.85938, 3.0625);
        symNewLine.addQuadPoint(6.85938, 3.0625, 6.85938, 3.0625, 6.875, 0, 6.875, 0);
        symTab.resize(0);
        symTab.addQuadPoint(4.82812, 3.96875, 4.82812, 3.96875, 4.5625, 3.73438, 4.5625, 3.96875);
        symTab.addQuadPoint(4.5625, 3.73438, 4.5625, 3.73438, 5.07812, 3.10938, 4.5625, 3.57812);
        symTab.addQuadPoint(5.07812, 3.10938, 5.07812, 3.10938, 0, 3.10938, 0, 3.10938);
        symTab.addQuadPoint(0, 3.10938, 0, 3.10938, 0, 2.625, 0, 2.625);
        symTab.addQuadPoint(0, 2.625, 0, 2.625, 5.53125, 2.625, 5.53125, 2.625);
        symTab.addQuadPoint(5.53125, 2.625, 5.53125, 2.625, 6.3125, 1.8125, 6.3125, 1.8125);
        symTab.addQuadPoint(6.3125, 1.8125, 6.3125, 1.8125, 5.64062, 1.29688, 5.64062, 1.29688);
        symTab.addQuadPoint(5.64062, 1.29688, 5.64062, 1.29688, 0, 1.29688, 0, 1.29688);
        symTab.addQuadPoint(0, 1.29688, 0, 1.29688, 0, 0.8125, 0, 0.8125);
        symTab.addQuadPoint(0, 0.8125, 0, 0.8125, 5.01562, 0.8125, 5.01562, 0.8125);
        symTab.addQuadPoint(5.01562, 0.8125, 5.01562, 0.8125, 4.45312, 0.265625, 4.45312, 0.453125);
        symTab.addQuadPoint(4.45312, 0.265625, 4.45312, 0.265625, 4.6875, 0, 4.45312, 0);
        symTab.addQuadPoint(4.6875, 0, 4.6875, 0, 5.90625, 0.828125, 4.875, 0);
        symTab.addQuadPoint(5.90625, 0.828125, 5.90625, 0.828125, 6.9375, 1.79688, 6.9375, 1.64062);
        symTab.addQuadPoint(6.9375, 1.79688, 6.9375, 1.79688, 5.95312, 2.96875, 6.9375, 1.95312);
        symTab.addQuadPoint(5.95312, 2.96875, 5.95312, 2.96875, 4.82812, 3.96875, 4.98438, 3.96875);
        symNonBreak.resize(0);
        symNonBreak.addQuadPoint(1.32812, 2.59375, 1.32812, 2.59375, 0.390625, 2.21875, 0.796875, 2.59375);
        symNonBreak.addQuadPoint(0.390625, 2.21875, 0.390625, 2.21875, 0, 1.3125, 0, 1.84375);
        symNonBreak.addQuadPoint(0, 1.3125, 0, 1.3125, 0.390625, 0.390625, 0, 0.765625);
        symNonBreak.addQuadPoint(0.390625, 0.390625, 0.390625, 0.390625, 1.32812, 0, 0.796875, 0);
        symNonBreak.addQuadPoint(1.32812, 0, 1.32812, 0, 2.23438, 0.390625, 1.85938, 0);
        symNonBreak.addQuadPoint(2.23438, 0.390625, 2.23438, 0.390625, 2.60938, 1.29688, 2.60938, 0.765625);
        symNonBreak.addQuadPoint(2.60938, 1.29688, 2.60938, 1.29688, 2.23438, 2.21875, 2.60938, 1.84375);
        symNonBreak.addQuadPoint(2.23438, 2.21875, 2.23438, 2.21875, 1.32812, 2.59375, 1.875, 2.59375);
        symNewCol.resize(0);
        symNewCol.addQuadPoint(1.73438, 0, 1.73438, 0, 2.67188, 0.109375, 2.03125, 0);
        symNewCol.addQuadPoint(2.67188, 0.109375, 2.67188, 0.109375, 3.59375, 0.203125, 3.26562, 0.21875);
        symNewCol.addQuadPoint(3.59375, 0.203125, 3.59375, 0.203125, 3.79688, 0.1875, 3.64062, 0.203125);
        symNewCol.addQuadPoint(3.79688, 0.1875, 3.79688, 0.1875, 4, 0.171875, 3.92188, 0.171875);
        symNewCol.addQuadPoint(4, 0.171875, 4, 0.171875, 4.20312, 0.1875, 4.20312, 0.1875);
        symNewCol.addQuadPoint(4.20312, 0.1875, 4.20312, 0.1875, 4.3125, 1.39062, 4.20312, 0.5625);
        symNewCol.addQuadPoint(4.3125, 1.39062, 4.3125, 1.39062, 4.42188, 2.64062, 4.42188, 2.21875);
        symNewCol.addQuadPoint(4.42188, 2.64062, 4.42188, 2.64062, 4.28125, 2.73438, 4.28125, 2.73438);
        symNewCol.addQuadPoint(4.28125, 2.73438, 4.28125, 2.73438, 3.75, 1.03125, 4.01562, 2.64062);
        symNewCol.addQuadPoint(3.75, 1.03125, 3.75, 1.03125, 3.67188, 1.03125, 3.67188, 1.03125);
        symNewCol.addQuadPoint(3.67188, 1.03125, 3.67188, 1.03125, 0.28125, 6.20312, 0.28125, 6.20312);
        symNewCol.addQuadPoint(0.28125, 6.20312, 0.28125, 6.20312, 0, 5.95312, 0.03125, 6.17188);
        symNewCol.addQuadPoint(0, 5.95312, 0, 5.95312, 3.35938, 0.71875, 3.35938, 0.71875);
        symNewCol.addQuadPoint(3.35938, 0.71875, 3.35938, 0.71875, 3.375, 0.640625, 3.375, 0.640625);
        symNewCol.addQuadPoint(3.375, 0.640625, 3.375, 0.640625, 2.4375, 0.484375, 2.79688, 0.5625);
        symNewCol.addQuadPoint(2.4375, 0.484375, 2.4375, 0.484375, 1.67188, 0.140625, 1.71875, 0.328125);
        symNewCol.addQuadPoint(1.67188, 0.140625, 1.67188, 0.140625, 1.73438, 0, 1.73438, 0);
        symNewFrame.resize(0);
        symNewFrame.addQuadPoint(1.75, 6.20312, 1.75, 6.20312, 2.67188, 6.09375, 2.0625, 6.20312);
        symNewFrame.addQuadPoint(2.67188, 6.09375, 2.67188, 6.09375, 3.60938, 5.98438, 3.28125, 5.98438);
        symNewFrame.addQuadPoint(3.60938, 5.98438, 3.60938, 5.98438, 3.84375, 6.01562, 3.6875, 5.98438);
        symNewFrame.addQuadPoint(3.84375, 6.01562, 3.84375, 6.01562, 4.07812, 6.03125, 4, 6.03125);
        symNewFrame.addQuadPoint(4.07812, 6.03125, 4.07812, 6.03125, 4.20312, 6.01562, 4.20312, 6.01562);
        symNewFrame.addQuadPoint(4.20312, 6.01562, 4.20312, 6.01562, 4.32812, 4.79688, 4.21875, 5.625);
        symNewFrame.addQuadPoint( 4.32812, 4.79688, 4.32812, 4.79688, 4.42188, 3.5625, 4.42188, 3.98438);
        symNewFrame.addQuadPoint(4.42188, 3.5625, 4.42188, 3.5625, 4.29688, 3.45312, 4.29688, 3.45312);
        symNewFrame.addQuadPoint(4.29688, 3.45312, 4.29688, 3.45312, 3.75, 5.17188, 4.03125, 3.54688);
        symNewFrame.addQuadPoint(3.75, 5.17188, 3.75, 5.17188, 3.67188, 5.17188, 3.67188, 5.17188);
        symNewFrame.addQuadPoint(3.67188, 5.17188, 3.67188, 5.17188, 0.28125, 0, 0.28125, 0);
        symNewFrame.addQuadPoint(0.28125, 0, 0.28125, 0, 0, 0.25, 0.03125, 0.015625);
        symNewFrame.addQuadPoint(0, 0.25, 0, 0.25, 3.375, 5.46875, 3.375, 5.46875);
        symNewFrame.addQuadPoint(3.375, 5.46875, 3.375, 5.46875, 3.39062, 5.54688, 3.39062, 5.54688);
        symNewFrame.addQuadPoint(3.39062, 5.54688, 3.39062, 5.54688, 2.4375, 5.70312, 2.8125, 5.625);
        symNewFrame.addQuadPoint(2.4375, 5.70312, 2.4375, 5.70312, 1.67188, 6.0625, 1.71875, 5.875);
        symNewFrame.addQuadPoint(1.67188, 6.0625, 1.67188, 6.0625, 1.75, 6.20312, 1.75, 6.20312);
}


ScPage* ScribusDoc::addPage(int pageNumber, const QString& masterPageName, bool addAutoFrame)
{
        assert(masterPageMode() == false);
        ScPage* addedPage = new ScPage(m_docPrefsData.displayPrefs.scratch.left(), DocPages.count()*(m_docPrefsData.docSetupPrefs.pageHeight+m_docPrefsData.displayPrefs.scratch.bottom()+m_docPrefsData.displayPrefs.scratch.top())+m_docPrefsData.displayPrefs.scratch.top(), m_docPrefsData.docSetupPrefs.pageWidth, m_docPrefsData.docSetupPrefs.pageHeight);
        assert(addedPage != nullptr);
        addedPage->setDocument(this);
        addedPage->Margins.setTop(m_docPrefsData.docSetupPrefs.margins.top());
        addedPage->Margins.setBottom(m_docPrefsData.docSetupPrefs.margins.bottom());
        addedPage->initialMargins = m_docPrefsData.docSetupPrefs.margins;
        addedPage->setPageNr(pageNumber);
        addedPage->setSize(m_docPrefsData.docSetupPrefs.pageSize);
        addedPage->setOrientation(m_docPrefsData.docSetupPrefs.pageOrientation);
        addedPage->marginPreset = m_docPrefsData.docSetupPrefs.marginPreset;
        DocPages.insert(pageNumber, addedPage);
        assert(DocPages.at(pageNumber) != nullptr);
        setCurrentPage(addedPage);
        if (!masterPageName.isEmpty())
                applyMasterPage(masterPageName, pageNumber);
        setLocationBasedPageLRMargins(pageNumber);
        if (addAutoFrame && m_automaticTextFrames)
                addAutomaticTextFrame(pageNumber);
        return addedPage;
}


ScPage* ScribusDoc::addMasterPage(int pageNumber, const QString& pageName)
{
        ScPage* addedPage = new ScPage(m_docPrefsData.displayPrefs.scratch.left(), m_docPrefsData.displayPrefs.scratch.top(), m_docPrefsData.docSetupPrefs.pageWidth, m_docPrefsData.docSetupPrefs.pageHeight);
        assert(addedPage != nullptr);
        addedPage->setDocument(this);
        addedPage->Margins = m_docPrefsData.docSetupPrefs.margins;
        addedPage->initialMargins = m_docPrefsData.docSetupPrefs.margins;
        addedPage->setSize(m_docPrefsData.docSetupPrefs.pageSize);
        addedPage->setOrientation(m_docPrefsData.docSetupPrefs.pageOrientation);
        addedPage->marginPreset = m_docPrefsData.docSetupPrefs.marginPreset;
        addedPage->clearMasterPageName();
        int pgN = pageNumber;
        if (pageNumber > MasterPages.count())
                pgN = MasterPages.count();
        addedPage->setPageName(pageName);
        addedPage->setPageNr(pgN);
        MasterNames.insert(pageName, pgN);
        MasterPages.insert(pgN, addedPage);
        assert(MasterPages.at(pgN) != nullptr);
        if (!isLoading())
                changed();
        if (UndoManager::undoEnabled())
        {
                auto *ss = new SimpleState(Um::NewMasterPage, "", Um::IDocument);
                ss->set("MASTERPAGE_ADD");
                ss->set("MASTERPAGE_NAME", pageName);
                ss->set("MASTERPAGE_NBR", pgN);
                m_undoManager->action(this, ss);
        }
        return addedPage;
}


bool ScribusDoc::renameMasterPage(const QString& oldPageName, const QString& newPageName)
{
        Q_ASSERT(oldPageName!=CommonStrings::masterPageNormal && oldPageName!=CommonStrings::trMasterPageNormal);
        if (!MasterNames.contains(oldPageName) || MasterNames.contains(newPageName))
                return false;

        //Rename our master page lists
        int number = MasterNames[oldPageName];
        MasterNames.insert(newPageName, number);
        MasterNames.remove(oldPageName);
        Q_ASSERT(MasterPages.at(number)->pageName() == oldPageName);
        MasterPages.at(number)->setPageName(newPageName);
        //Update any pages that were linking to our old name
        ScPage* docPage=nullptr;
        for (int i=0; i < DocPages.count(); ++i )
        {
                docPage=DocPages[i];
                if (docPage->masterPageName() == oldPageName)
                        docPage->setMasterPageName(newPageName);
        }
        //Update any items that were linking to our old name
        int masterItemsCount=MasterItems.count();
        for (int i = 0; i < masterItemsCount; ++i)
        {
                if (MasterItems.at(i)->OnMasterPage == oldPageName)
                        MasterItems.at(i)->setMasterPageName(newPageName);
        }
        changed();
        if (UndoManager::undoEnabled())
        {
                auto*ss = new SimpleState(Um::RenameMasterPage, "", Um::IDocument);
                ss->set("MASTERPAGE_RENAME");
                ss->set("OLD_MASTERPAGE", oldPageName);
                ss->set("NEW_MASTERPAGE", newPageName);
                m_undoManager->action(this, ss);
        }
        return true;
}


void ScribusDoc::deleteMasterPage(int pageNumber)
{
        assert(masterPageMode());
        assert( Pages->count() > 1 && Pages->count() > pageNumber );
        setCurrentPage(Pages->at(0));
        ScPage* page = Pages->takeAt(pageNumber);
        delete page;
        // #10658 : renumber masterpages and masterpage objects
        // in order to avoid crash after masterpage deletion
        for (int i = 0; i < MasterPages.count(); ++i)
                MasterPages.at(i)->setPageNr(i);
        for (int i = 0; i < MasterItems.count(); ++i)
        {
                if (MasterItems.at(i)->OwnPage > pageNumber)
                        MasterItems.at(i)->OwnPage--;
        }
        changed();
}


void ScribusDoc::rebuildMasterNames()
{
        MasterNames.clear();
        for (int i = 0; i < MasterPages.count(); ++i)
                MasterNames[MasterPages.at(i)->pageName()] = i;
}


void ScribusDoc::replaceMasterPage(const QString& oldMasterPage)
{
        uint pageIndex = 0;
        QMap<QString,int>::Iterator it = MasterNames.begin();
        QListIterator<ScPage *> dpIt(DocPages);
        ScPage* docPage=nullptr;
        while (dpIt.hasNext())
        {
                docPage = dpIt.next();
                if (docPage->masterPageName() == oldMasterPage)
                {
                        PageLocation pageLoc = locationOfPage(pageIndex);
                        if (pageLoc == LeftPage)
                        {
                                if (MasterNames.contains(CommonStrings::trMasterPageNormalLeft))
                                        docPage->setMasterPageName(CommonStrings::trMasterPageNormalLeft);
                                else if (MasterNames.contains(CommonStrings::trMasterPageNormal))
                                        docPage->setMasterPageNameNormal();
                                else
                                        docPage->setMasterPageName(it.key());
                        }
                        else if (pageLoc == RightPage)
                        {
                                if (MasterNames.contains(CommonStrings::trMasterPageNormalRight))
                                        docPage->setMasterPageName(CommonStrings::trMasterPageNormalRight);
                                else if (MasterNames.contains(CommonStrings::trMasterPageNormal))
                                        docPage->setMasterPageNameNormal();
                                else
                                        docPage->setMasterPageName(it.key());
                        }
                        else
                        {
                                if (MasterNames.contains(CommonStrings::trMasterPageNormalMiddle))
                                        docPage->setMasterPageName(CommonStrings::trMasterPageNormalMiddle);
                                else if (MasterNames.contains(CommonStrings::trMasterPageNormal))
                                        docPage->setMasterPageNameNormal();
                                else
                                        docPage->setMasterPageName(it.key());
                        }
                }
                pageIndex++;
        }
}


void ScribusDoc::deletePage(int pageNumber)
{
        assert( Pages->count() > 1 && Pages->count() > pageNumber );
        //#5561: If we are going to delete the first page, do not set the current page to it
        setCurrentPage(Pages->at(pageNumber!=0?0:1));
        ScPage* page = Pages->takeAt(pageNumber);
        delete page;
        reformPages();
        changed();
}

void ScribusDoc::swapPage(int a, int b)
{
        if (UndoManager::undoEnabled())
        {
                auto *ss = new SimpleState(Um::SwapPage, "", Um::IDocument);
                ss->set("PAGE_SWAP");
                ss->set("PAGE_SWAP_FROM", a);
                ss->set("PAGE_SWAP_TO", b);
                m_undoManager->action(this, ss);
        }
        Pages->swapItemsAt(a, b);
        reformPages();
        changed();
}

void ScribusDoc::restoreSwapPage(SimpleState* ss, bool isUndo)
{
        int a = ss->getInt("PAGE_SWAP_FROM");
        int b = ss->getInt("PAGE_SWAP_TO");

        if (isUndo)
                swapPage(b, a);
        else
                swapPage(a, b);
}

void ScribusDoc::movePage(int fromPage, int toPage, int dest, int position)
{
        QList<ScPage*> pageList;
        int numPages = dest;
        pageList.clear();
        for (int i = fromPage; i < toPage; ++i)
        {
                pageList.append(Pages->takeAt(fromPage));
                if (i <= numPages)
                        --numPages;
        }
        int pageListCount=pageList.count();
        switch (position)
        {
                case 0: //Before Page
                        for (int j = 0; j < pageListCount; ++j)
                                Pages->insert(numPages++, pageList.at(j));
                        break;
                case 1: //After Page
                        for (int j = 0; j < pageListCount; ++j)
                                Pages->insert(++numPages, pageList.at(j));
                        break;
                case 2: //To End
                        for (int j = 0; j < pageListCount; ++j)
                                Pages->append(pageList.at(j));
                        break;
        }

        if (UndoManager::undoEnabled())
        {
                auto *ss = new SimpleState(Um::MovePage, "", Um::IDocument);
                ss->set("PAGE_MOVE");
                ss->set("PAGE_MOVE_FROM", fromPage);
                ss->set("PAGE_MOVE_TO", toPage);
                ss->set("PAGE_MOVE_DEST", dest);
                ss->set("PAGE_MOVE_NEWPOS", position);
                m_undoManager->action(this, ss);
        }
        reformPages();
        if (m_View && m_ScMW)
        {
                m_View->reformPagesView();
                m_ScMW->updateGUIAfterPagesChanged();
        }
        updateEndnotesFrames();
        changed();
}

void ScribusDoc::restoreMovePage(SimpleState* ss, bool isUndo)
{
        int fromPage = ss->getInt("PAGE_MOVE_FROM");
        int toPage = ss->getInt("PAGE_MOVE_TO");
        int position = ss->getInt("PAGE_MOVE_NEWPOS");
        int dest = ss->getInt("PAGE_MOVE_DEST");

        if (isUndo)
        {
                int newPageDest = fromPage;
                int newPageFrom = 0;
                int newPageTo   = 0;
                int newPosition = 0;
                int pagesMoved  = toPage - fromPage;
                switch (position)
                {
                        case 0: //Before Page
                                newPageDest = (toPage <= dest) ? fromPage : toPage;
                                newPageFrom = (toPage <= dest) ? (dest - pagesMoved) : dest;
                                break;
                        case 1: //After Page
                                newPageDest = (toPage <= dest) ? fromPage : toPage;
                                newPageFrom = (toPage <= dest) ? (dest-pagesMoved + 1) : (dest + 1);
                                break;
                        case 2: //To End
                                newPageFrom = Pages->count() - pagesMoved;
                                break;
                }
                newPageTo = newPageFrom + pagesMoved;
                movePage(newPageFrom, newPageTo, newPageDest, newPosition);
        }
        else
                movePage(fromPage, toPage, dest, position);
}


int ScribusDoc::addAutomaticTextFrame(int pageNumber)
{
        if (!m_automaticTextFrames)
                return -1;
        ScPage *addToPage=DocPages.at(pageNumber);
        if ((!masterPageMode()) && (usesAutomaticTextFrames()))// && (!isLoading()))
        {
                int z = itemAdd(PageItem::TextFrame, PageItem::Unspecified,
                                                addToPage->Margins.left()+addToPage->xOffset(),
                                                addToPage->Margins.top()+addToPage->yOffset(), m_docPrefsData.docSetupPrefs.pageWidth-addToPage->Margins.right()-addToPage->Margins.left(),
                                                m_docPrefsData.docSetupPrefs.pageHeight-addToPage->Margins.bottom()-addToPage->Margins.top(),
                                                1, CommonStrings::None, m_docPrefsData.itemToolPrefs.shapeLineColor);
                Items->at(z)->isAutoText = true;
                Items->at(z)->m_columns = qRound(PageSp);
                Items->at(z)->m_columnGap = PageSpa;
                if (LastAuto != nullptr)
                        LastAuto->link(Items->at(z));
                else
                        FirstAuto = Items->at(z);
                LastAuto = Items->at(z);
                Items->at(z)->setRedrawBounding();
                updateEndnotesFrames();
                return z;
        }
        return -1;
}


int ScribusDoc::addLayer(const QString& layerName, bool activate)
{
        int lId = Layers.addLayer(layerName);
        if (lId==-1)
                return -1;
        if (activate)
                setActiveLayer(lId);
        const ScLayer* ll = Layers.layerByID(lId);
        if (!ll)
                qWarning() << "Layer added without undo, could not get layer back for undo action creation";
        else
                if (UndoManager::undoEnabled())
                {
                        auto *ss = new SimpleState(Um::AddLayer, "", Um::ICreate);
                        ss->set("ADD_LAYER");
                        ss->set("ACTIVE", m_ActiveLayer);
                        ss->set("NAME", ll->Name);
                        ss->set("LAYER_NR", ll->ID);
                        m_undoManager->action(this, ss, m_documentFileName, Um::ILayer);
                }

        changed();
        return lId;
}


void ScribusDoc::copyLayer(int layerIDToCopy, int whereToInsert)
{
        if (!setActiveLayer(whereToInsert))
                return;
        Selection sourceSelection(this);
        for (int ite = 0; ite < Items->count(); ++ite)
        {
                PageItem *itemToCopy = Items->at(ite);
                if (itemToCopy->m_layerID == layerIDToCopy)
                {
                        sourceSelection.addItem(itemToCopy);
                }
        }
        if (sourceSelection.count() != 0)
        {
                ScriXmlDoc ss;
                QString dataS = ss.writeElem(this, &sourceSelection);
                ss.readElemToLayer(dataS, this, Pages->at(0)->xOffset(), Pages->at(0)->yOffset(), false, true, whereToInsert);
        }
        sourceSelection.clear();
        changed();
}


bool ScribusDoc::deleteLayer(int layerID, bool deleteItems)
{
        if (Layers.count() < 2)
                return false;
        const ScLayer* lToRemove = Layers.layerByID(layerID);
        if (!lToRemove)
                return false;
        int layerLevel = lToRemove->Level;
        QString name   = lToRemove->Name;
        UndoTransaction activeTransaction;
        if (UndoManager::undoEnabled())
                activeTransaction = m_undoManager->beginTransaction(Um::Layer, Um::IDocument, Um::DeleteLayer, "", Um::IDelete);

        rebuildItemLists();
        if (ScCore->usingGUI())
                removeLayer(layerID, deleteItems);

        //Now delete the layer
        Layers.removeLayerByID(layerID);

        if (activeTransaction)
        {
                auto *ss = new SimpleState(Um::DeleteLayer, "", Um::IDelete);
                ss->set("REMOVE_LAYER");
                ss->set("ACTIVE", layerID);
                ss->set("LEVEL", layerLevel);
                ss->set("NAME", name);
                ss->set("LAYER_NR", layerID);
                ss->set("DELETE", deleteItems);
                m_undoManager->action(this, ss, m_documentFileName, Um::ILayer);
                activeTransaction.commit();
        }

        changed();
        return true;
}


int ScribusDoc::activeLayer()
{
        return m_ActiveLayer;
}


const QString& ScribusDoc::activeLayerName()
{
        const ScLayer* ll = Layers.layerByID(m_ActiveLayer);
        Q_ASSERT(ll);
        return ll->Name;
}


bool ScribusDoc::setActiveLayer(int layerToActivate)
{
        const ScLayer* ll = Layers.layerByID(layerToActivate);
        Q_ASSERT(ll);
        if (ll)
                m_ActiveLayer = layerToActivate;
        return (ll != nullptr);
}


bool ScribusDoc::setActiveLayer(const QString& layerNameToActivate)
{
        const ScLayer* ll = Layers.layerByName(layerNameToActivate);
        Q_ASSERT(ll);
        if (ll)
                m_ActiveLayer=ll->ID;
        return (ll != nullptr);
}


bool ScribusDoc::setLayerPrintable(int layerID, bool isPrintable)
{
        bool found = false;
        auto itend = Layers.end();
        for (auto it = Layers.begin(); it != itend; ++it)
        {
                if (it->ID == layerID)
                {
                        if (it->isPrintable!=isPrintable && UndoManager::undoEnabled())
                        {
                                auto *ss = new SimpleState(isPrintable ? Um::PrintLayer : Um::DoNotPrintLayer, "", Um::IPrint);
                                ss->set("PRINT_LAYER");
                                ss->set("ACTIVE", it->ID);
                                ss->set("PRINT", isPrintable);
                                m_undoManager->action(this, ss, it->Name, Um::ILayer);
                        }
                        it->isPrintable = isPrintable;
                        found=true;
                        break;
                }
        }
        if (found)
                changed();
        return found;
}


bool ScribusDoc::layerPrintable(int layerID) const
{
        auto itend = Layers.cend();
        for (auto it = Layers.cbegin(); it != itend; ++it)
        {
                if (it->ID == layerID)
                        return it->isPrintable;
        }
        return false;
}


bool ScribusDoc::setLayerVisible(int layerID, bool isViewable)
{
        bool found = false;
        auto itend = Layers.end();
        for (auto it = Layers.begin(); it != itend; ++it)
        {
                if (it->ID == layerID)
                {
                        it->isViewable = isViewable;
                        found=true;
                        break;
                }
        }
        if (found)
                changed();
        return found;
}


bool ScribusDoc::layerVisible(int layerID) const
{
        auto itend = Layers.cend();
        for (auto it = Layers.cbegin(); it != itend; ++it)
        {
                if (it->ID == layerID)
                        return it->isViewable;
        }
        return false;
}

bool ScribusDoc::setLayerSelectable(int layerID, bool isSelectable)
{
        bool found = false;
        auto itend = Layers.end();
        for (auto it = Layers.begin(); it != itend; ++it)
        {
                if (it->ID == layerID)
                {
                        it->isSelectable = isSelectable;
                        found=true;
                        break;
                }
        }
        if (found)
                changed();
        return found;
}


bool ScribusDoc::layerSelectable(int layerID) const
{
        auto itend = Layers.cend();
        for (auto it = Layers.cbegin(); it != itend; ++it)
        {
                if (it->ID == layerID)
                        return it->isSelectable;
        }
        return false;
}


bool ScribusDoc::setLayerLocked(int layerID, bool isLocked)
{
        bool found = false;
        auto itend = Layers.end();
        for (auto it = Layers.begin(); it != itend; ++it)
        {
                if (it->ID == layerID)
                {
                        // == because isEditable vs isLocked...
                        if (it->isEditable==isLocked && UndoManager::undoEnabled())
                        {
                                auto *ss = new SimpleState(isLocked ? Um::SetLayerLocked : Um::SetLayerUnlocked, "", Um::ILayer);
                                ss->set("LAYER_LOCK");
                                ss->set("ACTIVE", it->ID);
                                ss->set("LOCK", isLocked);
                                m_undoManager->action(this, ss, it->Name, Um::ILayer);
                        }
                        it->isEditable = !isLocked;
                        found=true;
                        break;
                }
        }
        if (found)
                changed();
        return found;
}


bool ScribusDoc::layerLocked(int layerID) const
{
        auto itend = Layers.cend();
        for (auto it = Layers.cbegin(); it != itend; ++it)
        {
                if (it->ID == layerID)
                        return !it->isEditable;
        }
        return false;
}


bool ScribusDoc::setLayerFlow(int layerID, bool flow)
{
        bool found = false;
        auto itend = Layers.end();
        for (auto it = Layers.begin(); it != itend; ++it)
        {
                if (it->ID == layerID)
                {
                        if (it->flowControl!=flow && UndoManager::undoEnabled())
                        {
                                auto *ss = new SimpleState(flow ? Um::FlowLayer : Um::DisableFlowLayer, "", Um::ITextFrame);
                                ss->set("LAYER_FLOW");
                                ss->set("ACTIVE", it->ID);
                                ss->set("FLOW", flow);
                                m_undoManager->action(this, ss, it->Name, Um::ILayer);
                        }
                        it->flowControl = flow;
                        found=true;
                        break;
                }
        }
        if (found)
        {
                // #9188 : invalidate layout of items below layer
                for (auto it = Layers.begin(); it != itend; ++it)
                {
                        if (it->ID == layerID)
                                break;
                        invalidateLayer(it->ID);
                }
                changed();
        }
        return found;
}


bool ScribusDoc::layerFlow(int layerID) const
{
        auto itend = Layers.cend();
        for (auto it = Layers.cbegin(); it != itend; ++it)
        {
                if (it->ID == layerID)
                        return it->flowControl;
        }
        return false;
}


bool ScribusDoc::setLayerTransparency(int layerID, double trans)
{
        bool found = false;
        auto itend = Layers.end();
        for (auto it = Layers.begin(); it != itend; ++it)
        {
                if (it->ID == layerID)
                {
                        if (it->transparency!=trans && UndoManager::undoEnabled())
                        {
                                auto *ss = new SimpleState(Um::SetLayerTransparency, "", Um::ILayer);
                                ss->set("LAYER_TRANSPARENCY");
                                ss->set("ACTIVE", it->ID);
                                ss->set("OLD_TRANS", it->transparency);
                                ss->set("NEW_TRANS", trans);
                                m_undoManager->action(this, ss, it->Name, Um::ILayer);
                        }
                        it->transparency = trans;
                        found=true;
                        break;
                }
        }
        if (found)
                changed();
        return found;
}


double ScribusDoc::layerTransparency(int layerID) const
{
        auto itend = Layers.cend();
        for (auto it = Layers.cbegin(); it != itend; ++it)
        {
                if (it->ID == layerID)
                        return it->transparency;
        }
        return 1.0;
}


bool ScribusDoc::setLayerBlendMode(int layerID, int blend)
{
        bool found = false;
        auto itend = Layers.end();
        for (auto it = Layers.begin(); it != itend; ++it)
        {
                if (it->ID == layerID)
                {
                        if (it->blendMode != blend && UndoManager::undoEnabled())
                        {
                                auto *ss = new SimpleState(Um::SetLayerBlendMode, "", Um::ILayer);
                                ss->set("LAYER_BLENDMODE");
                                ss->set("ACTIVE", it->ID);
                                ss->set("OLD_BLENDMODE", it->blendMode);
                                ss->set("NEW_BLENDMODE", blend);
                                m_undoManager->action(this, ss, it->Name, Um::ILayer);
                        }
                        it->blendMode = blend;
                        found=true;
                        break;
                }
        }
        if (found)
                changed();
        return found;
}


int ScribusDoc::layerBlendMode(int layerID) const
{
        auto itend = Layers.cend();
        for (auto it = Layers.cbegin(); it != itend; ++it)
        {
                if (it->ID == layerID)
                        return it->blendMode;
        }
        return 0;
}


bool ScribusDoc::setLayerOutline(int layerID, bool outline)
{
        bool found = false;
        auto itend = Layers.end();
        for (auto it = Layers.begin(); it != itend; ++it)
        {
                if (it->ID == layerID)
                {
                        it->outlineMode = outline;
                        found=true;
                        break;
                }
        }
        if (found)
                changed();
        return found;
}


bool ScribusDoc::layerOutline(int layerID) const
{
        auto  itend = Layers.cend();
        for (auto it = Layers.cbegin(); it != itend; ++it)
        {
                if (it->ID == layerID)
                        return it->outlineMode;
        }
        return false;
}


bool ScribusDoc::setLayerMarker(int layerID, const QColor& color)
{
        bool found = false;
        auto itend = Layers.end();
        for (auto it = Layers.begin(); it != itend; ++it)
        {
                if (it->ID == layerID)
                {
                        it->markerColor = color;
                        found=true;
                        break;
                }
        }
        if (found)
                changed();
        return found;
}


QColor ScribusDoc::layerMarker(int layerID) const
{
        auto itend = Layers.cend();
        for (auto it = Layers.cbegin(); it != itend; ++it)
        {
                if (it->ID == layerID)
                        return it->markerColor;
        }
        return QColor(0, 0, 0);
}


int ScribusDoc::layerLevelFromID(int layerID) const
{
        int layerCount = Layers.count();
        for (int i=0; i < layerCount; ++i)
        {
                const ScLayer& layer = Layers.at(i);
                if (layer.ID == layerID)
                        return layer.Level;
        }
        return -1;
}


int ScribusDoc::layerCount() const
{
        return Layers.count();
}


int ScribusDoc::layerIDFromLevel(int layerLevel) const
{
        int layerCount = Layers.count();
        for (int i = 0; i < layerCount; ++i)
        {
                const ScLayer& layer = Layers.at(i);
                if (layer.Level == layerLevel)
                        return layer.ID;
        }
        return -1;
}

int ScribusDoc::layerIDFromName(const QString& name) const
{
        auto itend = Layers.cend();
        for (auto it = Layers.cbegin(); it != itend; ++it)
        {
                if (it->Name == name)
                        return it->ID;
        }
        return -1;
}

bool ScribusDoc::lowerLayer(int layerID)
{
        return lowerLayerByLevel(layerLevelFromID(layerID));
}


bool ScribusDoc::lowerLayerByLevel(int layerLevel)
{
        if (layerLevel <= 0)
                return false;
        if (Layers.count() < 2)
                return false;
        if (UndoManager::undoEnabled())
        {
                auto *ss = new SimpleState(Um::LowerLayer, "", Um::IDown);
                ss->set("DOWN_LAYER");
                ss->set("ACTIVE", layerIDFromLevel(layerLevel));
                m_undoManager->action(this, ss, m_documentFileName, Um::ILayer);
        }

        ScLayers::iterator it;
        ScLayers::iterator itend=Layers.end();
        for (it = Layers.begin(); it != itend; ++it)
        {
                if (it->Level == layerLevel-1)
                        break;
        }
        ScLayers::iterator it2;
        ScLayers::iterator it2end=Layers.end();
        for (it2 = Layers.begin(); it2 != it2end; ++it2)
        {
                if (it2->Level == layerLevel)
                        break;
        }
        it2->Level -= 1;
        it->Level  += 1;
        // #9188 : invalidate layout of items in below layers
        int maxLevel = qMax(it->Level, it2->Level);
        for (it = Layers.begin(); it != itend; ++it)
        {
                if (it->flowControl)
                        invalidateLayer(it->ID);
                if (it->Level == maxLevel)
                        break;
        }
        return true;
}


bool ScribusDoc::raiseLayer(int layerID)
{
        return raiseLayerByLevel(layerLevelFromID(layerID));
}


bool ScribusDoc::raiseLayerByLevel(int layerLevel)
{
        if (layerLevel >= Layers.count() - 1)
                return false;
        if (Layers.count() < 2)
                return false;
        if (UndoManager::undoEnabled())
        {
                auto *ss = new SimpleState(Um::RaiseLayer, "", Um::IUp);
                ss->set("UP_LAYER");
                ss->set("ACTIVE", layerIDFromLevel(layerLevel));
                m_undoManager->action(this, ss, m_documentFileName, Um::ILayer);
        }

        ScLayers::iterator it;
        ScLayers::iterator itend = Layers.end();
        for (it = Layers.begin(); it != itend; ++it)
        {
                if (it->Level == layerLevel + 1)
                        break;
        }
        ScLayers::iterator it2;
        ScLayers::iterator it2end=Layers.end();
        for (it2 = Layers.begin(); it2 != it2end; ++it2)
        {
                if (it2->Level == layerLevel)
                        break;
        }
        it2->Level += 1;
        it->Level  -= 1;
        // #9188 : invalidate layout of items in below layers
        int maxLevel = qMax(it->Level, it2->Level);
        for (it = Layers.begin(); it != itend; ++it)
        {
                if (it->flowControl)
                        invalidateLayer(it->ID);
                if (it->Level == maxLevel)
                        break;
        }
        return true;
}


QString ScribusDoc::layerName(int layerID) const
{
        int layerCount = Layers.count();
        for (int i=0; i < layerCount; ++i)
        {
                const ScLayer& layer = Layers[i];
                if (layer.ID == layerID)
                        return layer.Name;
        }
        return QString();
}


bool ScribusDoc::changeLayerName(int layerID, const QString& newName)
{
        int layerCount=Layers.count();
        bool found=false;
        for (int i=0; i < layerCount; ++i)
        {
                if (Layers[i].ID == layerID)
                {
                        if (Layers[i].Name != newName)
                        {
                                if (UndoManager::undoEnabled())
                                {
                                        auto *ss = new SimpleState(Um::SetLayerName, QString(Um::FromTo).arg(Layers[i].Name, newName), Um::IDown);
                                        ss->set("CHANGE_NAME");
                                        ss->set("ACTIVE", m_ActiveLayer);
                                        ss->set("NEW_NAME", newName);
                                        ss->set("OLD_NAME", Layers[i].Name);
                                        m_undoManager->action(this, ss, m_documentFileName, Um::ILayer);
                                }
                                Layers[i].Name = newName;
                                found=true;
                        }
                        break;
                }
        }
        if (found)
                changed();
        return found;
}

bool ScribusDoc::canSelectItemOnLayer(int layerID) const
{
        if ((m_ActiveLayer != layerID) && !layerSelectable(layerID))
                return false;

        bool canSelect = layerVisible(layerID);
        if (!canSelect)
                return false;
        canSelect = !layerLocked(layerID);
        return canSelect;
}

bool ScribusDoc::layerContainsItems(int layerID) const
{
        QList<PageItem*> allItems;
        int masterItemsCount = MasterItems.count();
        for (int i = 0; i < masterItemsCount; ++i)
        {
                PageItem* currItem = MasterItems.at(i);
                if (currItem->isGroup())
                        allItems = currItem->getAllChildren();
                else
                        allItems.append(currItem);
                for (int ii = 0; ii < allItems.count(); ii++)
                {
                        currItem = allItems.at(ii);
                        if (currItem->m_layerID == layerID)
                                return true;
                }
                allItems.clear();
        }

        int docItemsCount = DocItems.count();
        for (int i = 0; i < docItemsCount; ++i)
        {
                PageItem* currItem = DocItems.at(i);
                if (currItem->isGroup())
                        allItems = currItem->getAllChildren();
                else
                        allItems.append(currItem);
                for (int ii = 0; ii < allItems.count(); ii++)
                {
                        currItem = allItems.at(ii);
                        if (currItem->m_layerID == layerID)
                                return true;
                }
                allItems.clear();
        }
        return false;
}


void ScribusDoc::orderedLayerList(QStringList* list) const
{
        Q_ASSERT(list != nullptr);

        int layerCount = Layers.count();
        if (layerCount == 0)
                return;

        for (int i=0; i < layerCount; ++i)
        {
                auto itend = Layers.cend();
                for (auto it = Layers.cbegin(); it != itend; ++it)
                {
                        if (layerCount - it->Level - 1 == i)
                                list->append(it->Name);
                }
        }
}

int ScribusDoc::firstLayerID() const
{
        QStringList newNames;
        orderedLayerList(&newNames);
        return layerIDFromName(newNames.first());
}

bool ScribusDoc::renumberLayer(int layerID, int newLayerID)
{
        int layerCount=Layers.count();
        int foundIndex = 0;
        bool found=false;
        //Find layer to renumber, if found the new number, return as it exists already.
        for (int i=0; i < layerCount; ++i)
        {
                if (Layers[i].ID == layerID)
                {
                        foundIndex=i;
                        found=true;
                }
                else
                if (Layers[i].ID == newLayerID)
                        return false;
        }
        if (!found)
                return false;
        Layers[foundIndex].ID=newLayerID;
        return true;
}

void ScribusDoc::replaceLineStyleColors(const QMap<QString, QString>& colorMap)
{
        multiLine::iterator its;
        QMap<QString, QString>::const_iterator it;
        for (auto itl = docLineStyles.begin(); itl != docLineStyles.end(); ++itl)
        {
                multiLine& mline = itl.value();
                for (its = mline.begin(); its != mline.end(); ++its)
                {
                        struct SingleLine& sline = *its;
                        it = colorMap.find(sline.Color);
                        if (it != colorMap.end())
                                sline.Color = it.value();
                }
        }
}

void ScribusDoc::getUsedColors(ColorList &colorsToUse, bool spot) const
{
        bool found;
        colorsToUse.clear();
        colorsToUse.setDocument(const_cast<ScribusDoc*>(this));

        ResourceCollection resources;
        this->getNamedResources(resources);
        const QMap<QString, QString>& resColors = resources.colors();

        for (auto it = PageColors.cbegin(); it != PageColors.cend(); ++it)
        {
                found = false;
                // Tool preferences colors
                if ((it.key() == m_docPrefsData.itemToolPrefs.shapeFillColor) || (it.key() == m_docPrefsData.itemToolPrefs.shapeLineColor) || (it.key() == m_docPrefsData.itemToolPrefs.imageFillColor)
                                 || (it.key() == m_docPrefsData.itemToolPrefs.imageStrokeColor) || (it.key() == m_docPrefsData.itemToolPrefs.lineColor) || (it.key() == m_docPrefsData.itemToolPrefs.textColor))
                {
                        if (spot)
                        {
                                if (it.value().isSpotColor())
                                        colorsToUse.insert(it.key(), it.value());
                        }
                        else
                                colorsToUse.insert(it.key(), it.value());
                        continue;
                }
                // Current paragraph style colors
                if ((it.key() == currentStyle.charStyle().fillColor()) || (it.key() == currentStyle.charStyle().strokeColor()) || (it.key() == currentStyle.charStyle().backColor()))
                        found = true;
                // Resources colors
                if (!found)
                        found = resColors.contains(it.key());
                // Line styles colors
                if (!found)
                        found = lineStylesUseColor(it.key());
                if (found)
                {
                        if (spot)
                        {
                                if (it.value().isSpotColor())
                                        colorsToUse.insert(it.key(), it.value());
                        }
                        else
                                colorsToUse.insert(it.key(), it.value());
                        continue;
                }
        }
}

ArrowDesc* ScribusDoc::arrowStyle(const QString& name)
{
        for (ArrowDesc& arrowDesc : m_docPrefsData.arrowStyles)
        {
                if (arrowDesc.name == name)
                        return &arrowDesc;
        }
        return nullptr;
}

bool ScribusDoc::hasArrowStyle(const QString& name) const
{
        for (const ArrowDesc& arrowDesc : m_docPrefsData.arrowStyles)
        {
                if (arrowDesc.name == name)
                        return true;
        }
        return false;
}

bool ScribusDoc::lineStylesUseColor(const QString& colorName) const
{
        bool found = false;
        multiLine::const_iterator its, itsend;
        auto itmend = docLineStyles.constEnd();
        for (auto itm = docLineStyles.constBegin(); itm != itmend && !found; ++itm)
        {
                const multiLine& ml = itm.value();
                itsend = ml.constEnd();
                for (its = ml.constBegin(); its != itsend; ++its)
                {
                        if (its->Color == colorName)
                        {
                                found = true;
                                break;
                        }
                }
        }
        return found;
}

void ScribusDoc::getUsedGradients(QHash<QString, VGradient> &gradients) const
{
        ResourceCollection resources;
        this->getNamedResources(resources);
        const QMap<QString, QString>& resGradients = resources.gradients();
        for (auto it = docGradients.cbegin(); it != docGradients.cend(); ++it)
        {
                if (resGradients.contains(it.key()))
                        gradients.insert(it.key(), it.value());
        }
}

bool ScribusDoc::addGradient(QString &name, const VGradient &gradient)
{
        for (auto it = docGradients.cbegin(); it != docGradients.cend(); ++it)
        {
                if (it.value() == gradient)
                {
                        name = it.key();
                        return false;
                }
        }
        QString tmp;
        if (docGradients.contains(name))
                name += "("+tmp.setNum(docGradients.count())+")";
        docGradients.insert(name, gradient);
        return true;
}

void ScribusDoc::setGradients(const QHash<QString, VGradient> &gradients)
{
        docGradients.clear();
        docGradients = gradients;
}

bool ScribusDoc::addPattern(QString &name, ScPattern& pattern)
{
        QString tmp;
        if (docPatterns.contains(name))
                name += "("+tmp.setNum(docPatterns.count())+")";
//              name = tr("Copy_of_")+name;
        docPatterns.insert(name, pattern);
        QList<PageItem*> allItems = getAllItems(pattern.items);
        for (int i = 0; i < allItems.count(); i++)
        {
                PageItem* currItem = allItems.at(i);
                currItem->setLayer(0);
        }
        return true;
}

void ScribusDoc::removePattern(const QString& name)
{
        docPatterns.remove(name);

        for (PageItemIterator it(this, PageItemIterator::IterateInDocDefaults); *it; ++it)
        {
                PageItem *currItem = *it;
                if (currItem->pattern() == name)
                        currItem->setPattern(QString());
                if (currItem->strokePattern() == name)
                        currItem->setStrokePattern(QString());
        }
}

ScPattern* ScribusDoc::checkedPattern(const QString &name)
{
        if (name.isEmpty() || !docPatterns.contains(name))
                return nullptr;
        ScPattern* pattern = &docPatterns[name];
        if (pattern->width <= 0 || pattern->height <= 0)
                return nullptr;
        if (pattern->getPattern()->isNull())
                return nullptr;
        return pattern;
}

void ScribusDoc::setPatterns(const QHash<QString, ScPattern> &patterns)
{
        docPatterns.clear();
        docPatterns = patterns;
}

QString ScribusDoc::getUniquePatternName(const QString& originalName) const
{
        if (!docPatterns.contains(originalName))
                return originalName;

        QString newName(originalName);

        // Search the string for (number) at the end and capture
        // both the number and the text leading up to it sans brackets.
        //     Copy of fred (5)
        //     ^^^^^^^^^^^^  ^   (where ^ means captured)
        QRegExp rx("^(.*)\\s+\\((\\d+)\\)$");
        int numMatches = rx.lastIndexIn(originalName);
        // Add a (number) suffix to the end of the name. We start at the
        // old suffix's value if there was one, or at 2 if there was not.
        int suffixNum = 1;
        QString prefix(newName);
        if (numMatches != -1)
        {
                // Already had a suffix; use the name w/o suffix for prefix and
                // grab the old suffix value as a starting point.
                QStringList matches = rx.capturedTexts();
                prefix = matches[1];
                suffixNum = matches[2].toInt();
        }
        // Keep on incrementing the suffix 'till we find a free name
        do
        {
                suffixNum ++;
                newName = prefix + " (" + QString::number(suffixNum) + ")";
        }
        while (docPatterns.contains(newName));

        return newName;
}

QStringList ScribusDoc::getUsedPatterns() const
{
        QList<PageItem*> allItems;
        QStringList results;

        for (PageItemIterator it(this, PageItemIterator::IterateInDocNoPatterns); *it; ++it)
        {
                PageItem* currItem = *it;
                if ((!results.contains(currItem->pattern())) && ((currItem->GrType == Gradient_Pattern) || (currItem->itemType() == PageItem::Symbol)))
                        results.append(currItem->pattern());
                if (!currItem->strokePattern().isEmpty())
                {
                        if (!results.contains(currItem->strokePattern()))
                                results.append(currItem->strokePattern());
                }
                if (!currItem->patternMask().isEmpty())
                {
                        if (!results.contains(currItem->patternMask()))
                                results.append(currItem->patternMask());
                }
        }

        for (auto it = docPatterns.constBegin(); it != docPatterns.constEnd(); ++it)
        {
                const ScPattern& pattern = it.value();
                for (int i = 0; i < pattern.items.count(); ++i)
                {
                        PageItem* currItem = pattern.items.at(i);
                        if (currItem->isGroup())
                                allItems = currItem->getAllChildren();
                        else
                                allItems.append(currItem);
                        for (int j = 0; j < allItems.count(); j++)
                        {
                                currItem = allItems.at(j);
                                if ((currItem->GrType == Gradient_Pattern) || (currItem->itemType() == PageItem::Symbol))
                                {
                                        const QString& patName = currItem->pattern();
                                        if (!patName.isEmpty() && !results.contains(patName))
                                                results.append(patName);
                                }
                                const QString& pat2 = currItem->strokePattern();
                                if (!pat2.isEmpty() && !results.contains(pat2))
                                        results.append(pat2);
                                const QString& pat3 = currItem->patternMask();
                                if (!pat3.isEmpty() && !results.contains(pat3))
                                        results.append(pat3);
                        }
                        allItems.clear();
                }
        }
        return results;
}


QStringList ScribusDoc::getUsedPatternsSelection(Selection* customSelection) const
{
        QStringList results;
        int selectedItemCount = customSelection->count();
        if (selectedItemCount == 0)
                return QStringList();

        for (int i = 0; i < selectedItemCount; ++i)
        {
                PageItem *currItem = customSelection->itemAt(i);
                QList<PageItem*> allItems;
                if (currItem->isGroup())
                        allItems = currItem->getAllChildren();
                else
                        allItems.append(currItem);
                for (int j = 0; j < allItems.count(); j++)
                {
                        currItem = allItems.at(j);
                        if ((currItem->GrType == Gradient_Pattern) || (currItem->itemType() == PageItem::Symbol))
                        {
                                const QString& pat = currItem->pattern();
                                if (!pat.isEmpty() && !results.contains(pat))
                                        results.append(currItem->pattern());
                        }
                        const QString& pat2 = currItem->strokePattern();
                        if (!pat2.isEmpty() && !results.contains(pat2))
                                results.append(currItem->strokePattern());
                        const QString& pat3 = currItem->patternMask();
                        if (!pat3.isEmpty() && !results.contains(pat3))
                                results.append(currItem->patternMask());
                }
                allItems.clear();
        }
        QStringList results2 = results;
        for (int i = 0; i < results.count(); ++i)
        {
                QStringList pats = getUsedPatternsHelper(results[i], results2);
                if (pats.isEmpty())
                        continue;
                for (int j = 0; j < pats.count(); j++)
                {
                        if (!results2.contains(pats[j]))
                                results2.append(pats[j]);
                }
        }
        return results2;
}

QStringList ScribusDoc::getUsedPatternsHelper(const QString& pattern, QStringList &results) const
{
        auto patIter = docPatterns.constFind(pattern);
        if (patIter == docPatterns.end())
                return QStringList();
        const ScPattern &pat = patIter.value();

        QStringList pats;
        for (int i = 0; i < pat.items.count(); ++i)
        {
                QList<PageItem*> allItems;
                if (pat.items.at(i)->isGroup())
                        allItems = pat.items.at(i)->getAllChildren();
                else
                        allItems.append(pat.items.at(i));
                for (int j = 0; j < allItems.count(); j++)
                {
                        PageItem *currItem = allItems.at(j);
                        if ((currItem->GrType == Gradient_Pattern) || (currItem->itemType() == PageItem::Symbol))
                        {
                                const QString& patName = currItem->pattern();
                                if (!patName.isEmpty() && !results.contains(patName))
                                        pats.append(patName);
                        }
                        const QString& pat2 = currItem->strokePattern();
                        if (!pat2.isEmpty() && !results.contains(pat2))
                                pats.append(currItem->strokePattern());
                        const QString& pat3 = currItem->patternMask();
                        if (!pat3.isEmpty() && !results.contains(pat3))
                                pats.append(currItem->patternMask());
                }
                allItems.clear();
        }
        if (!pats.isEmpty())
        {
                results += pats;
                for (int i = 0; i < pats.count(); ++i)
                {
                        QStringList pp = getUsedPatternsHelper(pats[i], results);
                        if (pp.isEmpty())
                                continue;
                        for (int cc = 0; cc < pp.count(); cc++)
                        {
                                if (!results.contains(pp[cc]))
                                        results.append(pp[cc]);
                        }
                }
        }
        return results;
}

QStringList ScribusDoc::getPatternDependencyList(const QStringList& used) const
{
        QStringList results;
        QStringList pp;
        QStringList pats = used;
        QStack<QStringList> patternStack;
        patternStack.push(pats);
        while (!pats.isEmpty())
        {
                for (int i = 0; i < pats.count(); ++i)
                {
                        pp = getUsedPatternsHelper(pats[i], results);
                }
                pats = results;
                results.clear();
                if (!pats.isEmpty())
                        patternStack.push(pats);
        }
        results.clear();
        while (patternStack.count() != 0)
        {
                pp = patternStack.pop();
                for (int i = 0; i < pp.count(); i++)
                {
                        if (!results.contains(pp[i]))
                                results.append(pp[i]);
                }
                if (patternStack.count() == 0)
                        break;
        }
        return results;
}

QStringList ScribusDoc::getUsedSymbols() const
{
        QStringList results;

        for (PageItemIterator it(this, PageItemIterator::IterateInDocDefaults); *it; ++it)
        {
                PageItem* currItem = *it;
                if (currItem->isGroup())
                        continue;
                if ((!results.contains(currItem->pattern())) && (currItem->itemType() == PageItem::Symbol) && (!currItem->pattern().isEmpty()))
                        results.append(currItem->pattern());
                if ((!currItem->strokePattern().isEmpty()) && (currItem->patternStrokePath))
                {
                        if (!results.contains(currItem->strokePattern()))
                                results.append(currItem->strokePattern());
                }
                if ((!results.contains(currItem->strokePattern())) && ((!currItem->strokePattern().isEmpty()) && (currItem->patternStrokePath)))
                        results.append(currItem->pattern());
        }
        return results;
}

QStringList ScribusDoc::getUsedSymbolsHelper(const QString& pattern, QStringList &results) const
{
        auto patIter = docPatterns.constFind(pattern);
        if (patIter == docPatterns.end())
                return QStringList();
        const ScPattern &pat = patIter.value();

        QStringList pats;
        for (int i = 0; i < pat.items.count(); ++i)
        {
                if (pat.items.at(i)->itemType() == PageItem::Symbol)
                {
                        const QString& patName = pat.items.at(i)->pattern();
                        if (!patName.isEmpty() && !results.contains(patName))
                                pats.append(patName);
                }
        }
        if (!pats.isEmpty())
        {
                for (int i = 0; i < pats.count(); ++i)
                        getUsedSymbolsHelper(pats[i], results);
        }
        return pats;
}

QMap<QString,int> ScribusDoc::reorganiseFonts()
{
        QMap<QString,int> Really;
        QList<PageItem*> allItems;

        bool wasMasterPageMode = m_masterPageMode;

        for (int i = 0; i < 2; ++i)
        {
                switch (i)
                {
                        case 0:
                                setMasterPageMode(true); // Necessary to avoid crash if some relayouting is necessary
                                allItems = MasterItems;
                                break;
                        case 1:
                                setMasterPageMode(false);
                                allItems = DocItems;
                                break;
                }
                PageItem* it = nullptr;
                while (allItems.count() > 0)
                {
                        it = allItems.takeFirst();
                        if (it->isGroup() || it->isTable(