View Issue Details
| ID | Project | Category | View Status | Date Submitted | Last Update |
|---|---|---|---|---|---|
| 0017986 | Scribus | Master Pages | public | 2026-09-27 05:45 | 2026-10-02 08:47 |
| Reporter | buttar | Assigned To | |||
| Priority | normal | Severity | feature | Reproducibility | N/A |
| Status | new | Resolution | open | ||
| Platform | Linux | OS | Fedora Workstation | OS Version | 44 |
| Product Version | 1.7.4.svn | ||||
| Summary | 0017986: [patch] Add True Spread Master Pages | ||||
| Description | This very useful feature has been asked for a lot in the past. All industry giants have this feature. Here is my much tested attempt on the same; a series of 6 small patches. You can build and test after each patch if you like (or the whole series at once). The TSM (true master spread) series depends on `mid-foundation-v1.00.patch` (from 0017984), which provides the persistent master-page ID and ID-based assignment foundation used to represent, track, rename, and apply logical master spreads safely. ## `tsm1-master-model-persistence-v1.01.patch` - Extends the master model with `MasterPageSide` (`Single`, `Left`, `Right`). - Allows two physical master pages to share one master ID, representing a logical facing spread. - Adds `masterPageIndices()`, side-aware `masterPageIndex()`, `masterPageHasSide()` and `isMasterSpread()`. - Persists master/applied side information in SLA and undo state. ## `tsm2-spread-editor-v1.16.patch` - Adds creation, duplication, editing and deletion support for logical two-page master spreads. - `ScribusDoc::addMasterSpread()` creates the paired Left/Right master pages under one ID. - Makes master-edit canvas/view handling spread-aware. - New Master UI exposes the valid facing choices directly: Spread, Single Left, Single Right; Duplicate Master follows the applicable subset. ## `tsm3-application-reflow-v1.05.patch` - Adds side-aware master application and document-spread targeting. - `documentSpreadPages()` resolves the physical left/right document pages; `applyMasterSpread()` applies both master halves as one undoable operation. - `matchingMasterPageSide()` and `reconcileMasterPageSides()` keep assignments valid across page movement and layout changes. - Preserves appropriate master margins during page-layout changes. ## `tsm4-cross-spread-rendering-v1.01.patch` - Makes on-canvas master rendering aware of both halves of an applied spread. - `masterItemsForAppliedPage()` resolves the master items relevant to each document page. - Allows artwork to cross the master spine while clipping its visible result to the appropriate physical page. ## `tsm5-output-projection-v1.06.patch` - Extends true-spread projection to PDF, PostScript/EPS, SVG, XPS and `ScPageOutput`. - `masterItemsForMasterPage()` provides the logical master item set used by output backends. - PDF/PS intersection and bleed handling project cross-spine artwork into each physical page's output/bleed region without exposing the opposite page. - SVG/XPS similarly clip each exported physical page to its own projection. ## `tsm6-default-master-lifecycle-normal-spread-v1.04.patch` - Adds the built-in Normal Spread master for two-column facing documents. - Centralizes built-in master roles/names and protection in `ScribusDoc`. - `ensureDefaultMasterPages()`, `reconcileDefaultMasterPages()` and `reconcileMasterPages()` keep required defaults and page assignments consistent after interactive layout changes. - Lifecycle handling is deliberately non-destructive: layout changes add/reconcile required defaults rather than silently deleting preserved masters. | ||||
| Tags | #please_test | ||||
| Attached Files | tsm1-master-model-persistence-v1.01.patch (20,959 bytes)
Index: scribus/plugins/fileloader/scribus171format/scribus171format.cpp
===================================================================
--- scribus/plugins/fileloader/scribus171format/scribus171format.cpp (revision 27864)
+++ scribus/plugins/fileloader/scribus171format/scribus171format.cpp (working copy)
@@ -4815,13 +4815,15 @@ bool Scribus171Format::readPage(ScribusDoc* doc, ScXmlStreamReader& reader)
bool savedMasterPageMode = m_Doc->masterPageMode();
m_Doc->setMasterPageMode(!pageName.isEmpty());
const QUuid storedMasterId(attrs.valueAsString("MasterPageId"));
- ScPage* newPage = pageName.isEmpty() ? doc->addPage(pageNum) : doc->addMasterPage(pageNum, pageName, storedMasterId);
+ const MasterPageSide masterSide = masterPageSideFromInt(attrs.valueAsInt("MasterPageSide", static_cast<int>(MasterPageSide::Single)));
+ ScPage* newPage = pageName.isEmpty() ? doc->addPage(pageNum) : doc->addMasterPage(pageNum, pageName, storedMasterId, masterSide);
//Remove uppercase in 1.8
if (attrs.hasAttribute("LEFT"))
newPage->LeftPg = attrs.valueAsInt("LEFT", 0);
else
newPage->LeftPg = attrs.valueAsInt("LeftPage", 0);
+ newPage->setMasterPageSide(masterSide);
//Remove uppercase in 1.8
QString mpName;
if (attrs.hasAttribute("MNAM"))
@@ -4835,6 +4837,7 @@ bool Scribus171Format::readPage(ScribusDoc* doc, ScXmlStreamReader& reader)
if (appliedId.isNull())
appliedId = doc->masterPageId(mpName);
newPage->setAppliedMasterPageId(appliedId);
+ newPage->setAppliedMasterPageSide(masterPageSideFromInt(attrs.valueAsInt("AppliedMasterPageSide", static_cast<int>(MasterPageSide::Single))));
}
if (attrs.hasAttribute("Size"))
newPage->setSize(attrs.valueAsString("Size"));
@@ -8363,11 +8366,13 @@ bool Scribus171Format::loadPage(const QString & fileName, int pageNumber, bool M
}
if (Mpage)
{
+ const MasterPageSide masterSide = masterPageSideFromInt(attrs.valueAsInt("MasterPageSide", static_cast<int>(MasterPageSide::Single)));
//Remove uppercase in 1.8
if (attrs.hasAttribute("LEFT"))
newPage->LeftPg = attrs.valueAsInt("LEFT", 0);
else
newPage->LeftPg = attrs.valueAsInt("LeftPage", 0);
+ newPage->setMasterPageSide(masterSide);
if (!renamedPageName.isEmpty())
newPage->setPageName(renamedPageName);
else
Index: scribus/plugins/fileloader/scribus171format/scribus171format_save.cpp
===================================================================
--- scribus/plugins/fileloader/scribus171format/scribus171format_save.cpp (revision 27864)
+++ scribus/plugins/fileloader/scribus171format/scribus171format_save.cpp (working copy)
@@ -1797,13 +1797,24 @@ void Scribus171Format::WritePages(ScribusDoc *doc, ScXmlStreamWriter& docu, QPro
docu.writeAttribute("PageName",page->pageName());
docu.writeAttribute("MasterPageName",page->masterPageName());
if (!page->masterPageId().isNull())
+ {
docu.writeAttribute("MasterPageId", page->masterPageId().toString(QUuid::WithoutBraces));
+ docu.writeAttribute("MasterPageSide", static_cast<int>(page->masterPageSide()));
+ }
if (!page->appliedMasterPageId().isNull())
+ {
docu.writeAttribute("AppliedMasterPageId", page->appliedMasterPageId().toString(QUuid::WithoutBraces));
+ docu.writeAttribute("AppliedMasterPageSide", static_cast<int>(page->appliedMasterPageSide()));
+ }
PageSize ps(page->width(), page->height());
docu.writeAttribute("Size", ps.name()); // legacy for Scribus < 1.7.4
docu.writeAttribute("Orientation", page->orientation());
- docu.writeAttribute("LeftPage", page->LeftPg);
+ int legacyLeftPage = page->LeftPg;
+ if (page->masterPageSide() == MasterPageSide::Left)
+ legacyLeftPage = 1;
+ else if (page->masterPageSide() == MasterPageSide::Right)
+ legacyLeftPage = 0;
+ docu.writeAttribute("LeftPage", legacyLeftPage);
docu.writeAttribute("Preset", page->marginPreset);
docu.writeAttribute("VerticalGuides", GuideManagerIO::writeVerticalGuides(page, GuideManagerCore::Standard));
docu.writeAttribute("HorizontalGuides", GuideManagerIO::writeHorizontalGuides(page, GuideManagerCore::Standard));
Index: scribus/scpage.cpp
===================================================================
--- scribus/scpage.cpp (revision 27864)
+++ scribus/scpage.cpp (working copy)
@@ -135,6 +135,7 @@ QString ScPage::masterPageName() const
void ScPage::setMasterPageName(const QString& newName)
{
m_masterPageName = newName;
+ m_appliedMasterPageSide = MasterPageSide::Single;
if (newName.isEmpty())
m_appliedMasterPageId = QUuid();
else if (m_Doc)
@@ -154,6 +155,7 @@ void ScPage::clearMasterPageName()
{
m_masterPageName.clear();
m_appliedMasterPageId = QUuid();
+ m_appliedMasterPageSide = MasterPageSide::Single;
}
void ScPage::setSize(const QString& newSize)
Index: scribus/scpage.h
===================================================================
--- scribus/scpage.h (revision 27864)
+++ scribus/scpage.h (working copy)
@@ -40,6 +40,27 @@ for which a new license (GPL+exception) is in place.
class PageItem;
class ScribusDoc;
+
+enum class MasterPageSide : int
+{
+ Single = 0,
+ Left,
+ Right
+};
+
+inline MasterPageSide masterPageSideFromInt(int value)
+{
+ switch (value)
+ {
+ case static_cast<int>(MasterPageSide::Left):
+ return MasterPageSide::Left;
+ case static_cast<int>(MasterPageSide::Right):
+ return MasterPageSide::Right;
+ default:
+ return MasterPageSide::Single;
+ }
+}
+
class UndoManager;
class UndoState;
@@ -95,8 +116,19 @@ public:
void setMasterPageName(const QString& newName);
const QUuid& masterPageId() const { return m_masterPageId; }
void setMasterPageId(const QUuid& id) { m_masterPageId = id; }
+ MasterPageSide masterPageSide() const { return m_masterPageSide; }
+ void setMasterPageSide(MasterPageSide side)
+ {
+ m_masterPageSide = side;
+ if (side == MasterPageSide::Left)
+ LeftPg = 1;
+ else if (side == MasterPageSide::Right)
+ LeftPg = 0;
+ }
const QUuid& appliedMasterPageId() const { return m_appliedMasterPageId; }
void setAppliedMasterPageId(const QUuid& id) { m_appliedMasterPageId = id; }
+ MasterPageSide appliedMasterPageSide() const { return m_appliedMasterPageSide; }
+ void setAppliedMasterPageSide(MasterPageSide side) { m_appliedMasterPageSide = side; }
void setMasterPageNameNormal();
void clearMasterPageName();
const QString& size() const {return m_pageSize;}
@@ -136,7 +168,9 @@ protected:
QString m_pageName;
QString m_masterPageName;
QUuid m_masterPageId;
+ MasterPageSide m_masterPageSide { MasterPageSide::Single };
QUuid m_appliedMasterPageId;
+ MasterPageSide m_appliedMasterPageSide { MasterPageSide::Single };
QString m_pageSize;
QString m_pageSectionNumber;
ScribusDoc* m_Doc {nullptr};
Index: scribus/scribus.cpp
===================================================================
--- scribus/scribus.cpp (revision 27864)
+++ scribus/scribus.cpp (working copy)
@@ -6168,7 +6168,9 @@ void ScribusMainWindow::deletePage(int from, int to)
ss->set("PAGENAME", doc->Pages->at(a)->pageName());
ss->set("MASTERPAGE", doc->Pages->at(a)->masterPageName());
ss->set("MASTER_PAGE_ID", doc->Pages->at(a)->masterPageId().toString(QUuid::WithoutBraces));
+ ss->set("MASTER_PAGE_SIDE", static_cast<int>(doc->Pages->at(a)->masterPageSide()));
ss->set("APPLIED_MASTER_PAGE_ID", doc->Pages->at(a)->appliedMasterPageId().toString(QUuid::WithoutBraces));
+ ss->set("APPLIED_MASTER_PAGE_SIDE", static_cast<int>(doc->Pages->at(a)->appliedMasterPageSide()));
ss->set("MASTER_PAGE_MODE", doc->masterPageMode());
// replace the deleted page in the undostack by a dummy object that will
// replaced with the "undone" page if user choose to undo the action
@@ -7963,6 +7965,8 @@ void ScribusMainWindow::restoreDeletePage(SimpleState *state, bool isUndo)
const QUuid restoredId(state->get("MASTER_PAGE_ID"));
if (!restoredId.isNull())
doc->Pages->at(pagenr - 1)->setMasterPageId(restoredId);
+ if (state->contains("MASTER_PAGE_SIDE"))
+ doc->Pages->at(pagenr - 1)->setMasterPageSide(static_cast<MasterPageSide>(state->getInt("MASTER_PAGE_SIDE")));
}
else
{
@@ -7970,6 +7974,8 @@ void ScribusMainWindow::restoreDeletePage(SimpleState *state, bool isUndo)
const QUuid restoredId(state->get("APPLIED_MASTER_PAGE_ID"));
if (!restoredId.isNull())
doc->Pages->at(pagenr - 1)->setAppliedMasterPageId(restoredId);
+ if (state->contains("APPLIED_MASTER_PAGE_SIDE"))
+ doc->Pages->at(pagenr - 1)->setAppliedMasterPageSide(static_cast<MasterPageSide>(state->getInt("APPLIED_MASTER_PAGE_SIDE")));
}
UndoObject *tmp =
m_undoManager->replaceObject(state->getUInt("DUMMY_ID"), doc->Pages->at(pagenr - 1));
Index: scribus/scribusdoc.cpp
===================================================================
--- scribus/scribusdoc.cpp (revision 27864)
+++ scribus/scribusdoc.cpp (working copy)
@@ -2061,22 +2061,28 @@ void ScribusDoc::restoreAddMasterPage(SimpleState* ss, bool isUndo)
ScPage* oldPage = currentPage();
setMasterPageMode(true);
+ const QUuid masterId(ss->get("MASTERPAGE_ID"));
+ const MasterPageSide side = ss->contains("MASTERPAGE_SIDE") ? static_cast<MasterPageSide>(ss->getInt("MASTERPAGE_SIDE")) : MasterPageSide::Single;
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);
+ const int masterIndex = masterId.isNull() ? MasterNames.value(pageName, -1) : masterPageIndex(masterId, side);
+ if (masterIndex >= 0)
+ {
+ auto *duo = new DummyUndoObject();
+ uint did = static_cast<uint>(duo->getUId());
+ m_undoManager->replaceObject(Pages->at(masterIndex)->getUId(), duo);
+ ss->set("DUMMY_ID", did);
- scMW()->deletePage2(MasterNames[pageName]);
- rebuildMasterNames();
- }
- else
+ scMW()->deletePage2(masterIndex);
+ rebuildMasterNames();
+ }
+ }
+ else
{
- ScPage* Mpage = addMasterPage(pageNr, pageName, QUuid(ss->get("MASTERPAGE_ID")));
+ ScPage* Mpage = addMasterPage(pageNr, pageName, masterId, side);
setCurrentPage(Mpage);
UndoObject *tmp = m_undoManager->replaceObject(
- ss->getUInt("DUMMY_ID"), Pages->at(MasterNames[pageName]));
+ ss->getUInt("DUMMY_ID"), Mpage);
delete tmp;
}
setMasterPageMode(oldMPMode);
@@ -2745,7 +2751,7 @@ ScPage* ScribusDoc::addPage(int pageNumber, const QString& masterPageName, bool
}
-ScPage* ScribusDoc::addMasterPage(int pageNumber, const QString& pageName, const QUuid& masterId)
+ScPage* ScribusDoc::addMasterPage(int pageNumber, const QString& pageName, const QUuid& masterId, MasterPageSide side)
{
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);
@@ -2762,9 +2768,16 @@ ScPage* ScribusDoc::addMasterPage(int pageNumber, const QString& pageName, const
addedPage->setPageName(pageName);
addedPage->setPageNr(pgN);
QUuid id = masterId;
- if (id.isNull() || MasterPageIds.contains(id))
+ if (id.isNull())
id = QUuid::createUuid();
+ else if (MasterPageIds.contains(id))
+ {
+ const bool sameLogicalMaster = (masterPageName(id) == pageName);
+ if (!sameLogicalMaster || masterPageHasSide(id, side))
+ id = QUuid::createUuid();
+ }
addedPage->setMasterPageId(id);
+ addedPage->setMasterPageSide(side);
MasterNames.insert(pageName, pgN);
MasterPages.insert(pgN, addedPage);
assert(MasterPages.at(pgN) != nullptr);
@@ -2781,6 +2794,7 @@ ScPage* ScribusDoc::addMasterPage(int pageNumber, const QString& pageName, const
ss->set("MASTERPAGE_NAME", pageName);
ss->set("MASTERPAGE_NBR", pgN);
ss->set("MASTERPAGE_ID", id.toString(QUuid::WithoutBraces));
+ ss->set("MASTERPAGE_SIDE", static_cast<int>(side));
m_undoManager->action(this, ss);
}
return addedPage;
@@ -2796,16 +2810,18 @@ bool ScribusDoc::renameMasterPage(const QString& oldPageName, const QString& new
bool ScribusDoc::renameMasterPage(const QUuid& masterId, const QString& newPageName)
{
- const int number = masterPageIndex(masterId);
- if (number < 0 || MasterNames.contains(newPageName))
+ const QList<int> indices = masterPageIndices(masterId);
+ if (indices.isEmpty())
+ return false;
+ const QString oldPageName = MasterPages.at(indices.first())->pageName();
+ if (oldPageName != newPageName && MasterNames.contains(newPageName))
return false;
- const QString oldPageName = MasterPages.at(number)->pageName();
Q_ASSERT(oldPageName != CommonStrings::masterPageNormal && oldPageName != CommonStrings::trMasterPageNormal);
- MasterNames.remove(oldPageName);
- MasterNames.insert(newPageName, number);
- MasterPages.at(number)->setPageName(newPageName);
+ for (int index : indices)
+ MasterPages.at(index)->setPageName(newPageName);
+ rebuildMasterNames();
// Master item names remain as a compatibility mirror for legacy code and files.
for (PageItem* item : std::as_const(MasterItems))
@@ -2859,10 +2875,35 @@ void ScribusDoc::rebuildMasterNames()
for (int i = 0; i < MasterPages.count(); ++i)
{
ScPage* master = MasterPages.at(i);
- if (master->masterPageId().isNull() || MasterPageIds.contains(master->masterPageId()))
- master->setMasterPageId(QUuid::createUuid());
- MasterNames[master->pageName()] = i;
- MasterPageIds[master->masterPageId()] = i;
+ QUuid id = master->masterPageId();
+ if (id.isNull())
+ {
+ id = QUuid::createUuid();
+ master->setMasterPageId(id);
+ }
+
+ QList<int>& indices = MasterPageIds[id];
+ bool invalidSharedId = !indices.isEmpty() && MasterPages.at(indices.first())->pageName() != master->pageName();
+ for (int existingIndex : std::as_const(indices))
+ {
+ if (MasterPages.at(existingIndex)->masterPageSide() == master->masterPageSide())
+ {
+ invalidSharedId = true;
+ break;
+ }
+ }
+ if (invalidSharedId)
+ {
+ id = QUuid::createUuid();
+ master->setMasterPageId(id);
+ MasterPageIds[id].append(i);
+ }
+ else
+ indices.append(i);
+
+ // Names remain a compatibility lookup for the logical master.
+ if (!MasterNames.contains(master->pageName()))
+ MasterNames[master->pageName()] = i;
}
}
@@ -2880,10 +2921,44 @@ QString ScribusDoc::masterPageName(const QUuid& masterId) const
return index >= 0 ? MasterPages.at(index)->pageName() : QString();
}
+QList<int> ScribusDoc::masterPageIndices(const QUuid& masterId) const
+{
+ return MasterPageIds.value(masterId);
+}
+
int ScribusDoc::masterPageIndex(const QUuid& masterId) const
{
- auto it = MasterPageIds.constFind(masterId);
- return it == MasterPageIds.constEnd() ? -1 : it.value();
+ const QList<int> indices = masterPageIndices(masterId);
+ if (indices.isEmpty())
+ return -1;
+
+ for (int index : indices)
+ {
+ if (MasterPages.at(index)->masterPageSide() == MasterPageSide::Single)
+ return index;
+ }
+ return indices.first();
+}
+
+int ScribusDoc::masterPageIndex(const QUuid& masterId, MasterPageSide side) const
+{
+ const QList<int> indices = masterPageIndices(masterId);
+ for (int index : indices)
+ {
+ if (MasterPages.at(index)->masterPageSide() == side)
+ return index;
+ }
+ return -1;
+}
+
+bool ScribusDoc::masterPageHasSide(const QUuid& masterId, MasterPageSide side) const
+{
+ return masterPageIndex(masterId, side) >= 0;
+}
+
+bool ScribusDoc::isMasterSpread(const QUuid& masterId) const
+{
+ return masterPageHasSide(masterId, MasterPageSide::Left) && masterPageHasSide(masterId, MasterPageSide::Right);
}
@@ -4892,14 +4967,25 @@ bool ScribusDoc::applyMasterPage(const QString& pageName, int pageNumber)
bool ScribusDoc::applyMasterPage(const QUuid& masterId, int pageNumber)
{
- const int MpNr = masterPageIndex(masterId);
+ const int index = masterPageIndex(masterId);
+ if (index < 0)
+ return false;
+ return applyMasterPage(masterId, MasterPages.at(index)->masterPageSide(), pageNumber);
+}
+
+bool ScribusDoc::applyMasterPage(const QUuid& masterId, MasterPageSide side, int pageNumber)
+{
+ int MpNr = masterPageIndex(masterId, side);
+ if (MpNr < 0 && side != MasterPageSide::Single)
+ MpNr = masterPageIndex(masterId, MasterPageSide::Single);
if (MpNr < 0)
return false;
+ const MasterPageSide appliedSide = MasterPages.at(MpNr)->masterPageSide();
const QString pageName = MasterPages.at(MpNr)->pageName();
if (UndoManager::undoEnabled())
{
- if (DocPages.at(pageNumber)->masterPageName() != pageName)
+ if (DocPages.at(pageNumber)->appliedMasterPageId() != masterId || DocPages.at(pageNumber)->appliedMasterPageSide() != appliedSide)
{
auto *ss = new SimpleState(Um::ApplyMasterPage, QString(Um::FromTo).arg(DocPages.at(pageNumber)->masterPageName(), pageName));
ss->set("PAGE_NUMBER", pageNumber);
@@ -4907,12 +4993,15 @@ bool ScribusDoc::applyMasterPage(const QUuid& masterId, int pageNumber)
ss->set("NEW_MASTERPAGE", pageName);
ss->set("OLD_MASTERPAGE_ID", DocPages.at(pageNumber)->appliedMasterPageId().toString(QUuid::WithoutBraces));
ss->set("NEW_MASTERPAGE_ID", masterId.toString(QUuid::WithoutBraces));
+ ss->set("OLD_MASTERPAGE_SIDE", static_cast<int>(DocPages.at(pageNumber)->appliedMasterPageSide()));
+ ss->set("NEW_MASTERPAGE_SIDE", static_cast<int>(appliedSide));
m_undoManager->action(this, ss);
}
}
ScPage* Ap = DocPages.at(pageNumber);
Ap->setMasterPageName(pageName);
Ap->setAppliedMasterPageId(masterId);
+ Ap->setAppliedMasterPageSide(appliedSide);
const ScPage* Mp = MasterPages.at(MpNr);
PageItem *currItem;
Ap->FromMaster.clear();
@@ -4998,9 +5087,15 @@ void ScribusDoc::restoreMasterPageApplying(SimpleState* ss, bool isUndo)
const QUuid oldId(ss->get("OLD_MASTERPAGE_ID"));
const QUuid newId(ss->get("NEW_MASTERPAGE_ID"));
if (isUndo)
- applyMasterPage(oldId.isNull() ? masterPageId(ss->get("OLD_MASTERPAGE")) : oldId, pageNumber);
+ {
+ const MasterPageSide side = ss->contains("OLD_MASTERPAGE_SIDE") ? static_cast<MasterPageSide>(ss->getInt("OLD_MASTERPAGE_SIDE")) : MasterPageSide::Single;
+ applyMasterPage(oldId.isNull() ? masterPageId(ss->get("OLD_MASTERPAGE")) : oldId, side, pageNumber);
+ }
else
- applyMasterPage(newId.isNull() ? masterPageId(ss->get("NEW_MASTERPAGE")) : newId, pageNumber);
+ {
+ const MasterPageSide side = ss->contains("NEW_MASTERPAGE_SIDE") ? static_cast<MasterPageSide>(ss->getInt("NEW_MASTERPAGE_SIDE")) : MasterPageSide::Single;
+ applyMasterPage(newId.isNull() ? masterPageId(ss->get("NEW_MASTERPAGE")) : newId, side, pageNumber);
+ }
reformPages();
scMW()->pagePalette->rebuildPages();
}
Index: scribus/scribusdoc.h
===================================================================
--- scribus/scribusdoc.h (revision 27864)
+++ scribus/scribusdoc.h (working copy)
@@ -261,13 +261,17 @@ class SCRIBUS_API ScribusDoc : public QObject, public UndoObject, public Observa
ScPage* addPage(int pageNumber, const QString& masterPageName = QString(), bool addAutoFrame = false);
void deletePage(int);
//! @brief Add a master page with this function, do not use addPage
- ScPage* addMasterPage(int, const QString&, const QUuid& masterId = QUuid());
+ ScPage* addMasterPage(int, const QString&, const QUuid& masterId = QUuid(), MasterPageSide side = MasterPageSide::Single);
void deleteMasterPage(int);
//! @brief Rebuild master name list
void rebuildMasterNames();
QUuid masterPageId(const QString& pageName) const;
QString masterPageName(const QUuid& masterId) const;
+ QList<int> masterPageIndices(const QUuid& masterId) const;
int masterPageIndex(const QUuid& masterId) const;
+ int masterPageIndex(const QUuid& masterId, MasterPageSide side) const;
+ bool masterPageHasSide(const QUuid& masterId, MasterPageSide side) const;
+ bool isMasterSpread(const QUuid& masterId) const;
//! @brief Replace a master page by default one
void replaceMasterPage(const QString& oldMasterPage);
//! @brief Rename a master page
@@ -839,6 +843,7 @@ class SCRIBUS_API ScribusDoc : public QObject, public UndoObject, public Observa
*/
bool applyMasterPage(const QString& pageName, int pageNumber);
bool applyMasterPage(const QUuid& masterId, int pageNumber);
+ bool applyMasterPage(const QUuid& masterId, MasterPageSide side, int pageNumber);
/**
* @brief Undo function for applying a master page
*/
@@ -1415,7 +1420,7 @@ class SCRIBUS_API ScribusDoc : public QObject, public UndoObject, public Observa
QList<ScPage*> TempPages;
/** \brief Mapping Master Page Name to Master Page numbers */
QMap<QString,int> MasterNames;
- QHash<QUuid, int> MasterPageIds;
+ QHash<QUuid, QList<int>> MasterPageIds;
/** \brief List of Objects */
//! Items is a pointer to the lists of items that exist in a document. In Normal mode, it points to DocItems. In Master Page mode it points to MasterItems. See ScribusDoc::assignPageModeLists()
QList<PageItem*>* Items {nullptr};
tsm2-spread-editor-v1.16.patch (76,195 bytes)
Index: scribus/canvas.cpp
===================================================================
--- scribus/canvas.cpp (revision 27864)
+++ scribus/canvas.cpp (working copy)
@@ -17,6 +17,7 @@
#define _USE_MATH_DEFINES
#endif
#include <cmath>
+#include <utility>
// #include <QDebug>
#include <QToolTip>
@@ -467,7 +468,7 @@
while (currNr >= 0)
{
currItem = itemList->at(currNr);
- if ((m_doc->masterPageMode()) && (!((currItem->OwnPage == -1) || (currItem->OwnPage == m_doc->currentPage()->pageNr()))))
+ if (m_doc->masterPageMode() && !m_doc->isMasterItemOnCurrentMaster(currItem))
{
--currNr;
continue;
@@ -1429,7 +1430,6 @@
qRound(clip.width() / m_viewMode.scale + 0.5), qRound(clip.height() / m_viewMode.scale + 0.5));
PageItem *currItem { nullptr };
- int docCurrPageNo = m_doc->currentPageNumber();
if (((layer.blendMode != 0) || (layer.transparency != 1.0)) && (!layer.outlineMode))
painter->beginLayer(layer.transparency, layer.blendMode);
@@ -1446,7 +1446,7 @@
|| (currItem->m_layerID != layer.ID)
|| (m_viewMode.previewMode && !currItem->printEnabled())
|| (m_viewMode.viewAsPreview && (!currItem->printEnabled()))
- || (m_doc->masterPageMode() && ((currItem->OwnPage != -1) && (currItem->OwnPage != docCurrPageNo)))
+ || (m_doc->masterPageMode() && !m_doc->isMasterItemOnCurrentMaster(currItem))
|| ((!m_doc->masterPageMode() && !currItem->OnMasterPage.isEmpty()) && (currItem->OnMasterPage != m_doc->currentPage()->pageName())))
continue;
if (cullingArea.intersects(currItem->getBoundingRect().adjusted(0.0, 0.0, 1.0, 1.0)))
@@ -1466,7 +1466,7 @@
continue;
if ((m_viewMode.viewAsPreview) && (!currItem->printEnabled()))
continue;
- if ((m_doc->masterPageMode()) && ((currItem->OwnPage != -1) && (currItem->OwnPage != docCurrPageNo)))
+ if (m_doc->masterPageMode() && !m_doc->isMasterItemOnCurrentMaster(currItem))
continue;
if (!m_doc->masterPageMode() && !currItem->OnMasterPage.isEmpty())
{
@@ -1505,43 +1505,67 @@
painter->endLayer();
}
+QList<const ScPage*> Canvas::masterEditPages() const
+{
+ QList<const ScPage*> pages;
+ const ScPage* currentPage = m_doc->currentPage();
+ if (!currentPage)
+ return pages;
+
+ const QList<int> indices = m_doc->masterPageIndices(currentPage->masterPageId());
+ if (indices.isEmpty())
+ {
+ pages.append(currentPage);
+ return pages;
+ }
+
+ for (int index : indices)
+ {
+ if (index >= 0 && index < m_doc->MasterPages.count())
+ pages.append(m_doc->MasterPages.at(index));
+ }
+ return pages;
+}
+
+
/**
Draws the canvas background for masterpages, incl. bleeds
*/
void Canvas::drawBackgroundMasterpage(ScPainter* painter, int clipx, int clipy, int clipw, int cliph)
{
- const ScPage* currentPage = m_doc->currentPage();
- double x = currentPage->xOffset() * m_viewMode.scale;
- double y = currentPage->yOffset() * m_viewMode.scale;
- double w = currentPage->width() * m_viewMode.scale;
- double h = currentPage->height() * m_viewMode.scale;
- QRectF drawRect(x, y, w + 5, h + 5);
- drawRect.translate(-m_doc->minCanvasCoordinate.x() * m_viewMode.scale, -m_doc->minCanvasCoordinate.y() * m_viewMode.scale);
- if (!drawRect.intersects(QRectF(clipx, clipy, clipw, cliph)))
- return;
+ for (const ScPage* page : masterEditPages())
+ {
+ double x = page->xOffset() * m_viewMode.scale;
+ double y = page->yOffset() * m_viewMode.scale;
+ double w = page->width() * m_viewMode.scale;
+ double h = page->height() * m_viewMode.scale;
+ QRectF drawRect(x, y, w + 5, h + 5);
+ drawRect.translate(-m_doc->minCanvasCoordinate.x() * m_viewMode.scale, -m_doc->minCanvasCoordinate.y() * m_viewMode.scale);
+ if (!drawRect.intersects(QRectF(clipx, clipy, clipw, cliph)))
+ continue;
- painter->setFillMode(ScPainter::Solid);
- painter->setBrush(QColor(128,128,128));
- MarginStruct pageBleeds;
- if (!m_doc->bleeds()->isNull() && m_doc->guidesPrefs().showBleed)
- m_doc->getBleeds(currentPage, pageBleeds);
- if (m_viewMode.viewAsPreview)
- pageBleeds.resetToZero();
- double px = currentPage->xOffset() - pageBleeds.left();
- double py = currentPage->yOffset() - pageBleeds.top();
- double pw = currentPage->width() + pageBleeds.left() + pageBleeds.right();
- double ph = currentPage->height() + pageBleeds.bottom() + pageBleeds.top();
- painter->setAntialiasing(false);
- painter->setPen(Qt::black, 1 / m_viewMode.scale, Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin);
- if (PrefsManager::instance().appPrefs.displayPrefs.showPageShadow)
- painter->drawRect(px + 5, py + 5, pw, ph);
- painter->setBrush(m_doc->paperColor());
- painter->drawRect(px, py, pw, ph);
- painter->setAntialiasing(true);
+ painter->setFillMode(ScPainter::Solid);
+ painter->setBrush(QColor(128,128,128));
+ MarginStruct pageBleeds;
+ if (!m_doc->bleeds()->isNull() && m_doc->guidesPrefs().showBleed)
+ m_doc->getBleeds(page, pageBleeds);
+ if (m_viewMode.viewAsPreview)
+ pageBleeds.resetToZero();
+ double px = page->xOffset() - pageBleeds.left();
+ double py = page->yOffset() - pageBleeds.top();
+ double pw = page->width() + pageBleeds.left() + pageBleeds.right();
+ double ph = page->height() + pageBleeds.bottom() + pageBleeds.top();
+ painter->setAntialiasing(false);
+ painter->setPen(Qt::black, 1 / m_viewMode.scale, Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin);
+ if (PrefsManager::instance().appPrefs.displayPrefs.showPageShadow)
+ painter->drawRect(px + 5, py + 5, pw, ph);
+ painter->setBrush(m_doc->paperColor());
+ painter->drawRect(px, py, pw, ph);
+ painter->setAntialiasing(true);
+ }
}
-
/**
draws the page outlines on canvas, including bleed area
*/
@@ -1674,22 +1698,23 @@
{
PoLine->resize(0);
bool first = true;
- ScPage *actPg;
+ const ScPage *actPg;
- int firstPage = 0;
- int lastPage = m_doc->Pages->count();
+ QList<const ScPage*> pages;
if (m_doc->Pages == &m_doc->MasterPages)
+ pages = masterEditPages();
+ else
{
- firstPage = m_doc->currentPage()->pageNr();
- lastPage = firstPage + 1;
+ for (const ScPage* page : std::as_const(*m_doc->Pages))
+ pages.append(page);
}
- for (int i = firstPage; i < lastPage; ++i)
+ for (const ScPage* page : std::as_const(pages))
{
if (!first)
PoLine->setMarker();
first = false;
- actPg = m_doc->Pages->at(i);
+ actPg = page;
double x = actPg->xOffset();
double y = actPg->yOffset();
double w = actPg->width();
@@ -1728,15 +1753,13 @@
{
if (master)
{
- const ScPage *page = m_doc->currentPage();
- double x = m_doc->scratch()->left() * m_viewMode.scale;
- double y = m_doc->scratch()->top() * m_viewMode.scale;
- double w = page->width() * m_viewMode.scale;
- double h = page->height() * m_viewMode.scale;
- QRectF drawRect(x, y, w + 5, h + 5);
- drawRect.translate(-m_doc->minCanvasCoordinate.x() * m_viewMode.scale, -m_doc->minCanvasCoordinate.y() * m_viewMode.scale);
- if (drawRect.intersects(clip))
- DrawPageBorderSub(p, page);
+ for (const ScPage* page : masterEditPages())
+ {
+ QRectF drawRect(page->xOffset() * m_viewMode.scale, page->yOffset() * m_viewMode.scale, page->width() * m_viewMode.scale + 5, page->height() * m_viewMode.scale + 5);
+ drawRect.translate(-m_doc->minCanvasCoordinate.x() * m_viewMode.scale, -m_doc->minCanvasCoordinate.y() * m_viewMode.scale);
+ if (drawRect.intersects(clip))
+ DrawPageBorderSub(p, page);
+ }
}
else
{
@@ -1790,15 +1813,13 @@
{
if (master)
{
- const ScPage *page = m_doc->currentPage();
- double x = m_doc->scratch()->left() * m_viewMode.scale;
- double y = m_doc->scratch()->top() * m_viewMode.scale;
- double w = page->width() * m_viewMode.scale;
- double h = page->height() * m_viewMode.scale;
- QRectF drawRect(x, y, w + 5, h + 5);
- drawRect.translate(-m_doc->minCanvasCoordinate.x() * m_viewMode.scale, -m_doc->minCanvasCoordinate.y() * m_viewMode.scale);
- if (drawRect.intersects(clip))
- DrawPageMarginsGridSub(p, page);
+ for (const ScPage* page : masterEditPages())
+ {
+ QRectF drawRect(page->xOffset() * m_viewMode.scale, page->yOffset() * m_viewMode.scale, page->width() * m_viewMode.scale + 5, page->height() * m_viewMode.scale + 5);
+ drawRect.translate(-m_doc->minCanvasCoordinate.x() * m_viewMode.scale, -m_doc->minCanvasCoordinate.y() * m_viewMode.scale);
+ if (drawRect.intersects(clip))
+ DrawPageMarginsGridSub(p, page);
+ }
}
else
{
@@ -1844,15 +1865,13 @@
if (master)
{
- const ScPage *page = m_doc->currentPage();
- double x = m_doc->scratch()->left() * m_viewMode.scale;
- double y = m_doc->scratch()->top() * m_viewMode.scale;
- double w = page->width() * m_viewMode.scale;
- double h = page->height() * m_viewMode.scale;
- QRectF drawRect(x, y, w + 5, h + 5);
- drawRect.translate(-m_doc->minCanvasCoordinate.x() * m_viewMode.scale, -m_doc->minCanvasCoordinate.y() * m_viewMode.scale);
- if (drawRect.intersects(clip))
- DrawPageBaselineGridSub(p, page);
+ for (const ScPage* page : masterEditPages())
+ {
+ QRectF drawRect(page->xOffset() * m_viewMode.scale, page->yOffset() * m_viewMode.scale, page->width() * m_viewMode.scale + 5, page->height() * m_viewMode.scale + 5);
+ drawRect.translate(-m_doc->minCanvasCoordinate.x() * m_viewMode.scale, -m_doc->minCanvasCoordinate.y() * m_viewMode.scale);
+ if (drawRect.intersects(clip))
+ DrawPageBaselineGridSub(p, page);
+ }
}
else
{
@@ -1972,15 +1991,13 @@
if (master)
{
- const ScPage *page = m_doc->currentPage();
- double x = m_doc->scratch()->left() * m_viewMode.scale;
- double y = m_doc->scratch()->top() * m_viewMode.scale;
- double w = page->width() * m_viewMode.scale;
- double h = page->height() * m_viewMode.scale;
- QRectF drawRect(x, y, w + 5, h + 5);
- drawRect.translate(-m_doc->minCanvasCoordinate.x() * m_viewMode.scale, -m_doc->minCanvasCoordinate.y() * m_viewMode.scale);
- if (drawRect.intersects(clip))
- DrawPageGridSub(p, page, clip);
+ for (const ScPage* page : masterEditPages())
+ {
+ QRectF drawRect(page->xOffset() * m_viewMode.scale, page->yOffset() * m_viewMode.scale, page->width() * m_viewMode.scale + 5, page->height() * m_viewMode.scale + 5);
+ drawRect.translate(-m_doc->minCanvasCoordinate.x() * m_viewMode.scale, -m_doc->minCanvasCoordinate.y() * m_viewMode.scale);
+ if (drawRect.intersects(clip))
+ DrawPageGridSub(p, page, clip);
+ }
}
else
{
@@ -2023,15 +2040,13 @@
if (master)
{
- const ScPage *page = m_doc->currentPage();
- double x = m_doc->scratch()->left() * m_viewMode.scale;
- double y = m_doc->scratch()->top() * m_viewMode.scale;
- double w = page->width() * m_viewMode.scale;
- double h = page->height() * m_viewMode.scale;
- QRectF drawRect(x, y, w + 5, h + 5);
- drawRect.translate(-m_doc->minCanvasCoordinate.x() * m_viewMode.scale, -m_doc->minCanvasCoordinate.y() * m_viewMode.scale);
- if (drawRect.intersects(clip))
- DrawPageGuidesSub(p, page);
+ for (const ScPage* page : masterEditPages())
+ {
+ QRectF drawRect(page->xOffset() * m_viewMode.scale, page->yOffset() * m_viewMode.scale, page->width() * m_viewMode.scale + 5, page->height() * m_viewMode.scale + 5);
+ drawRect.translate(-m_doc->minCanvasCoordinate.x() * m_viewMode.scale, -m_doc->minCanvasCoordinate.y() * m_viewMode.scale);
+ if (drawRect.intersects(clip))
+ DrawPageGuidesSub(p, page);
+ }
}
else
{
@@ -2074,8 +2089,8 @@
if (master)
{
const ScPage *page = m_doc->currentPage();
- double x = m_doc->scratch()->left() * m_viewMode.scale;
- double y = m_doc->scratch()->top() * m_viewMode.scale;
+ double x = page->xOffset() * m_viewMode.scale;
+ double y = page->yOffset() * m_viewMode.scale;
double w = page->width() * m_viewMode.scale;
double h = page->height() * m_viewMode.scale;
QRectF drawRect(x, y, w + 5, h + 5);
Index: scribus/canvas.h
===================================================================
--- scribus/canvas.h (revision 27864)
+++ scribus/canvas.h (working copy)
@@ -25,6 +25,7 @@
#define CANVAS_H
#include <QApplication>
+#include <QList>
//#include <QDebug>
#include <QPolygon>
#include <QRect>
@@ -248,6 +249,7 @@
*/
void fillBuffer(QPaintDevice* buffer, QPoint bufferOrigin, QRect clipRect);
void drawContents(QPainter *p, int clipx, int clipy, int clipw, int cliph);
+ QList<const ScPage*> masterEditPages() const;
void drawBackgroundMasterpage(ScPainter* painter, int clipx, int clipy, int clipw, int cliph);
void drawBackgroundPageOutlines(ScPainter* painter, int clipx, int clipy, int clipw, int cliph);
void drawControls(QPainter* p);
Index: scribus/canvasmode_edit.cpp
===================================================================
--- scribus/canvasmode_edit.cpp (revision 27864)
+++ scribus/canvasmode_edit.cpp (working copy)
@@ -909,7 +909,7 @@
m_canvas->Transform(docItem, p);
QRegion apr = QRegion(docItem->Clip * p);
QRect apr2(docItem->getRedrawBounding(1.0));
- if ((m_doc->masterPageMode()) && (docItem->OnMasterPage != m_doc->currentPage()->pageName()))
+ if (m_doc->masterPageMode() && !m_doc->isMasterItemOnCurrentMaster(docItem))
continue;
if (((Sele.contains(apr.boundingRect())) || (Sele.contains(apr2))) && m_doc->canSelectItemOnLayer(docItem->m_layerID))
{
Index: scribus/canvasmode_normal.cpp
===================================================================
--- scribus/canvasmode_normal.cpp (revision 27864)
+++ scribus/canvasmode_normal.cpp (working copy)
@@ -1207,7 +1207,7 @@
for (int a = 0; a < docItemCount; ++a)
{
PageItem* docItem = m_doc->Items->at(a);
- if ((m_doc->masterPageMode()) && (docItem->OnMasterPage != m_doc->currentPage()->pageName()))
+ if (m_doc->masterPageMode() && !m_doc->isMasterItemOnCurrentMaster(docItem))
continue;
if (m_doc->canSelectItemOnLayer(docItem->m_layerID))
{
Index: scribus/plugins/fileloader/scribus171format/scribus171format.cpp
===================================================================
--- scribus/plugins/fileloader/scribus171format/scribus171format.cpp (revision 27864)
+++ scribus/plugins/fileloader/scribus171format/scribus171format.cpp (working copy)
@@ -4995,7 +4995,10 @@
{
if (!readObjectParams.renamedMasterPage.isEmpty())
masterPageName = readObjectParams.renamedMasterPage;
- doc->setCurrentPage(doc->MasterPages.at(doc->MasterNames[masterPageName]));
+ if (readObjectParams.destinationMasterPage >= 0 && readObjectParams.destinationMasterPage < doc->MasterPages.count())
+ doc->setCurrentPage(doc->MasterPages.at(readObjectParams.destinationMasterPage));
+ else
+ doc->setCurrentPage(doc->MasterPages.at(doc->MasterNames[masterPageName]));
pageNr = -2;
}
layerFound = false;
@@ -5010,7 +5013,20 @@
newItem->setMasterPageId(itemMasterId);
newItem->setRedrawBounding();
if (tagName == QLatin1String("MASTEROBJECT") || tagName == QLatin1String("MasterObject"))
- newItem->setOwnerPage(doc->OnPage(newItem));
+ {
+ int ownerPage = readObjectParams.destinationMasterPage;
+ if (ownerPage < 0)
+ {
+ const int storedOwner = attrs.valueAsInt("OwnPage", -1);
+ if (storedOwner >= 0 && storedOwner < doc->MasterPages.count())
+ {
+ const ScPage* storedPage = doc->MasterPages.at(storedOwner);
+ if (itemMasterId.isNull() || storedPage->masterPageId() == itemMasterId)
+ ownerPage = storedOwner;
+ }
+ }
+ newItem->setOwnerPage(ownerPage >= 0 ? ownerPage : doc->OnPage(newItem));
+ }
else
newItem->setOwnerPage(attrs.valueAsInt("OwnPage"));
if ((tagName == QLatin1String("PAGEOBJECT") || tagName == QLatin1String("PageObject")) || (tagName == QLatin1String("ITEM") || tagName == QLatin1String("Item")))
@@ -8337,6 +8353,7 @@
continue;
int pageNr = m_Doc->currentPage()->pageNr();
newPage = m_Doc->Pages->at(pageNr);
+ readObjectParams.destinationMasterPage = Mpage ? pageNr : -1;
SimpleState *ss = nullptr;
if (UndoManager::undoEnabled())
{
@@ -8509,7 +8526,7 @@
PageItem* newItem = itemInfo.item;
newItem->moveBy(-pageX + newPage->xOffset(), - pageY + newPage->yOffset());
- newItem->setOwnerPage(m_Doc->currentPageNumber());
+ newItem->setOwnerPage(Mpage ? newPage->pageNr() : m_Doc->currentPageNumber());
if (tagName == QLatin1String("PAGEOBJECT") || tagName == QLatin1String("PageObject"))
newItem->setMasterPageName(QString());
else if (Mpage && !renamedPageName.isEmpty())
Index: scribus/plugins/fileloader/scribus171format/scribus171format.h
===================================================================
--- scribus/plugins/fileloader/scribus171format/scribus171format.h (revision 27864)
+++ scribus/plugins/fileloader/scribus171format/scribus171format.h (working copy)
@@ -113,6 +113,7 @@
bool loadingPage { false };
QString baseDir;
QString renamedMasterPage;
+ int destinationMasterPage {-1};
};
void registerFormats();
Index: scribus/plugins/scripter/api_document.cpp
===================================================================
--- scribus/plugins/scripter/api_document.cpp (revision 27864)
+++ scribus/plugins/scripter/api_document.cpp (working copy)
@@ -521,10 +521,7 @@
RAISE("Can not delete the Normal master page");
return;
}
- bool oldMode = ScCore->primaryMainWindow()->doc->masterPageMode();
- ScCore->primaryMainWindow()->doc->setMasterPageMode(true);
- ScCore->primaryMainWindow()->deletePage2(ScCore->primaryMainWindow()->doc->MasterNames[name]);
- ScCore->primaryMainWindow()->doc->setMasterPageMode(oldMode);
+ ScCore->primaryMainWindow()->deleteMasterPage(name);
}
void DocumentAPI::closeMasterPage(QString name)
Index: scribus/plugins/scriptplugin/cmddoc.cpp
===================================================================
--- scribus/plugins/scriptplugin/cmddoc.cpp (revision 27864)
+++ scribus/plugins/scriptplugin/cmddoc.cpp (working copy)
@@ -507,10 +507,7 @@
PyErr_SetString(PyExc_ValueError, "Can not delete the Normal master page");
return nullptr;
}
- bool oldMode = currentDoc->masterPageMode();
- currentDoc->setMasterPageMode(true);
- ScCore->primaryMainWindow()->deletePage2(currentDoc->MasterNames[masterPageName]);
- currentDoc->setMasterPageMode(oldMode);
+ ScCore->primaryMainWindow()->deleteMasterPage(masterPageName);
Py_RETURN_NONE;
}
Index: scribus/scpage.cpp
===================================================================
--- scribus/scpage.cpp (revision 27864)
+++ scribus/scpage.cpp (working copy)
@@ -437,11 +437,43 @@
PageItem* oldItem = itemList.at(id2);
if (oldItem->Parent && oldItem->Parent->isGroup())
oldItem->Parent->asGroupFrame()->groupItemList.insert(id, oldItem);
+ else if (state->contains("STABLE_ITEM_ORDER") && state->getBool("STABLE_ITEM_ORDER"))
+ {
+ int insertIndex = -1;
+ if (state->contains("NEXT_ITEM_UID"))
+ {
+ const quint64 nextUid = state->getUInt64("NEXT_ITEM_UID");
+ for (int i = 0; i < m_Doc->Items->count(); ++i)
+ {
+ if (m_Doc->Items->at(i)->getUId() == nextUid)
+ {
+ insertIndex = i;
+ break;
+ }
+ }
+ }
+ if ((insertIndex < 0) && state->contains("PREV_ITEM_UID"))
+ {
+ const quint64 prevUid = state->getUInt64("PREV_ITEM_UID");
+ for (int i = 0; i < m_Doc->Items->count(); ++i)
+ {
+ if (m_Doc->Items->at(i)->getUId() == prevUid)
+ {
+ insertIndex = i + 1;
+ break;
+ }
+ }
+ }
+ if (insertIndex < 0)
+ insertIndex = qBound(0, id, m_Doc->Items->count());
+ m_Doc->Items->insert(insertIndex, oldItem);
+ }
else
m_Doc->Items->insert(id, oldItem);
if (oldItem->isBookmark)
m_Doc->scMW()->AddBookMark(oldItem);
- m_Doc->m_Selection->addItems(itemList);
+ if (!state->contains("RESTORE_SELECTION") || state->getBool("RESTORE_SELECTION"))
+ m_Doc->m_Selection->addItems(itemList);
}
else
{
Index: scribus/scribus.cpp
===================================================================
--- scribus/scribus.cpp (revision 27864)
+++ scribus/scribus.cpp (working copy)
@@ -6104,6 +6104,46 @@
deletePage(pg + 1, pg + 1);
}
+void ScribusMainWindow::deleteMasterPage(const QString& masterPageName)
+{
+ if (!HaveDoc)
+ return;
+
+ const QUuid masterId = doc->masterPageId(masterPageName);
+ QList<int> masterIndices = doc->masterPageIndices(masterId);
+ if (masterIndices.isEmpty())
+ return;
+
+ std::sort(masterIndices.begin(), masterIndices.end());
+ const bool oldMasterPageMode = doc->masterPageMode();
+ ScPage* oldPage = oldMasterPageMode ? nullptr : doc->currentPage();
+ doc->setMasterPageMode(true);
+
+ bool contiguous = true;
+ for (int i = 1; i < masterIndices.count(); ++i)
+ {
+ if (masterIndices.at(i) != masterIndices.at(i - 1) + 1)
+ {
+ contiguous = false;
+ break;
+ }
+ }
+
+ if (masterIndices.count() == 1)
+ deletePage2(masterIndices.first());
+ else if (contiguous)
+ deletePage(masterIndices.first() + 1, masterIndices.last() + 1);
+ else
+ {
+ for (int i = masterIndices.count() - 1; i >= 0; --i)
+ deletePage2(masterIndices.at(i));
+ }
+
+ doc->setMasterPageMode(oldMasterPageMode);
+ if (oldPage)
+ doc->setCurrentPage(oldPage);
+}
+
void ScribusMainWindow::deletePage()
{
if (HaveDoc && doc->appMode == modeEditClip)
@@ -6130,6 +6170,25 @@
PageItem* ite;
doc->m_Selection->clear();
Selection tmpSelection(this, false);
+ bool deletingMasterSpread = false;
+ QStringList deletedMasterNames;
+ if (doc->masterPageMode())
+ {
+ for (int a = to - 1; a >= from - 1; --a)
+ {
+ const ScPage* masterPage = doc->Pages->at(a);
+ if (doc->isMasterSpread(masterPage->masterPageId()))
+ deletingMasterSpread = true;
+ if (!deletedMasterNames.contains(masterPage->pageName()))
+ deletedMasterNames.append(masterPage->pageName());
+ }
+
+ // Reassign document pages while the masters still exist. The resulting
+ // ApplyMasterPage undo states then live in the same transaction as the
+ // master deletion, so Undo restores the masters before reapplying them.
+ for (const QString& masterName : std::as_const(deletedMasterNames))
+ doc->replaceMasterPage(masterName);
+ }
for (int a = to - 1; a >= from - 1; a--)
{
for (int d = 0; d < doc->Items->count(); ++d)
@@ -6155,7 +6214,11 @@
page->guides.clearVerticals(GuideManagerCore::Auto);
}
if (tmpSelection.count() != 0)
- doc->itemSelection_DeleteItem(&tmpSelection);
+ {
+ const auto selectionPolicy = deletingMasterSpread ? ScribusDoc::ItemDeletionSelectionPolicy::DoNotRestore : ScribusDoc::ItemDeletionSelectionPolicy::Restore;
+ const auto orderPolicy = deletingMasterSpread ? ScribusDoc::ItemDeletionOrderPolicy::StableNeighbors : ScribusDoc::ItemDeletionOrderPolicy::OriginalIndex;
+ doc->itemSelection_DeleteItem(&tmpSelection, false, selectionPolicy, orderPolicy);
+ }
const QSignalBlocker blocker(pageSelector);
view->updatesOn(false);
for (int a = to - 1; a >= from - 1; a--)
@@ -6169,6 +6232,22 @@
ss->set("MASTERPAGE", doc->Pages->at(a)->masterPageName());
ss->set("MASTER_PAGE_ID", doc->Pages->at(a)->masterPageId().toString(QUuid::WithoutBraces));
ss->set("MASTER_PAGE_SIDE", static_cast<int>(doc->Pages->at(a)->masterPageSide()));
+ if (doc->masterPageMode())
+ {
+ const ScPage* masterPage = doc->Pages->at(a);
+ ss->set("MASTER_PAGE_LEFT", masterPage->LeftPg);
+ ss->set("MASTER_PAGE_INITIALTOP", masterPage->initialMargins.top());
+ ss->set("MASTER_PAGE_INITIALBOTTOM", masterPage->initialMargins.bottom());
+ ss->set("MASTER_PAGE_INITIALLEFT", masterPage->initialMargins.left());
+ ss->set("MASTER_PAGE_INITIALRIGHT", masterPage->initialMargins.right());
+ ss->set("MASTER_PAGE_INITIALHEIGHT", masterPage->initialHeight());
+ ss->set("MASTER_PAGE_INITIALWIDTH", masterPage->initialWidth());
+ ss->set("MASTER_PAGE_HEIGHT", masterPage->height());
+ ss->set("MASTER_PAGE_WIDTH", masterPage->width());
+ ss->set("MASTER_PAGE_ORIENTATION", masterPage->orientation());
+ ss->set("MASTER_PAGE_SIZE", masterPage->size());
+ ss->set("MASTER_PAGE_MARGINPRESET", masterPage->marginPreset);
+ }
ss->set("APPLIED_MASTER_PAGE_ID", doc->Pages->at(a)->appliedMasterPageId().toString(QUuid::WithoutBraces));
ss->set("APPLIED_MASTER_PAGE_SIDE", static_cast<int>(doc->Pages->at(a)->appliedMasterPageSide()));
ss->set("MASTER_PAGE_MODE", doc->masterPageMode());
@@ -7959,26 +8038,44 @@
if (isUndo)
{
+ ScPage* restoredPage = nullptr;
if (savedMasterPageMode)
{
- slotNewMasterPage(wo, pageName);
const QUuid restoredId(state->get("MASTER_PAGE_ID"));
- if (!restoredId.isNull())
- doc->Pages->at(pagenr - 1)->setMasterPageId(restoredId);
- if (state->contains("MASTER_PAGE_SIDE"))
- doc->Pages->at(pagenr - 1)->setMasterPageSide(static_cast<MasterPageSide>(state->getInt("MASTER_PAGE_SIDE")));
+ const MasterPageSide restoredSide = state->contains("MASTER_PAGE_SIDE")
+ ? masterPageSideFromInt(state->getInt("MASTER_PAGE_SIDE"))
+ : MasterPageSide::Single;
+ restoredPage = doc->addMasterPage(wo, pageName, restoredId, restoredSide);
+ if (restoredSide == MasterPageSide::Single && state->contains("MASTER_PAGE_LEFT"))
+ restoredPage->LeftPg = state->getInt("MASTER_PAGE_LEFT");
+ if (state->contains("MASTER_PAGE_INITIALTOP"))
+ {
+ restoredPage->initialMargins.setTop(state->getDouble("MASTER_PAGE_INITIALTOP"));
+ restoredPage->initialMargins.setBottom(state->getDouble("MASTER_PAGE_INITIALBOTTOM"));
+ restoredPage->initialMargins.setLeft(state->getDouble("MASTER_PAGE_INITIALLEFT"));
+ restoredPage->initialMargins.setRight(state->getDouble("MASTER_PAGE_INITIALRIGHT"));
+ restoredPage->setInitialHeight(state->getDouble("MASTER_PAGE_INITIALHEIGHT"));
+ restoredPage->setInitialWidth(state->getDouble("MASTER_PAGE_INITIALWIDTH"));
+ restoredPage->setHeight(state->getDouble("MASTER_PAGE_HEIGHT"));
+ restoredPage->setWidth(state->getDouble("MASTER_PAGE_WIDTH"));
+ restoredPage->setOrientation(state->getInt("MASTER_PAGE_ORIENTATION"));
+ restoredPage->setSize(state->get("MASTER_PAGE_SIZE"));
+ restoredPage->marginPreset = state->getInt("MASTER_PAGE_MARGINPRESET");
+ }
+ view->addPage(wo);
}
else
{
addNewPages(wo, where, 1, doc->pageHeight(), doc->pageWidth(), doc->pageOrientation(), doc->pageSize(), true, &tmpl);
+ restoredPage = doc->Pages->at(pagenr - 1);
const QUuid restoredId(state->get("APPLIED_MASTER_PAGE_ID"));
if (!restoredId.isNull())
- doc->Pages->at(pagenr - 1)->setAppliedMasterPageId(restoredId);
+ restoredPage->setAppliedMasterPageId(restoredId);
if (state->contains("APPLIED_MASTER_PAGE_SIDE"))
- doc->Pages->at(pagenr - 1)->setAppliedMasterPageSide(static_cast<MasterPageSide>(state->getInt("APPLIED_MASTER_PAGE_SIDE")));
+ restoredPage->setAppliedMasterPageSide(static_cast<MasterPageSide>(state->getInt("APPLIED_MASTER_PAGE_SIDE")));
}
UndoObject *tmp =
- m_undoManager->replaceObject(state->getUInt("DUMMY_ID"), doc->Pages->at(pagenr - 1));
+ m_undoManager->replaceObject(state->getUInt("DUMMY_ID"), restoredPage);
delete tmp;
}
else
@@ -7992,7 +8089,10 @@
if (currMasterPageMode != savedMasterPageMode)
doc->setMasterPageMode(currMasterPageMode);
doc->rebuildMasterNames();
- pagePalette->updateMasterPageList();
+ if (isUndo && savedMasterPageMode)
+ editMasterPagesStart(pageName);
+ else
+ pagePalette->updateMasterPageList();
pagePalette->rebuildPages();
if (outlinePalette->isVisible())
outlinePalette->BuildTree();
Index: scribus/scribus.h
===================================================================
--- scribus/scribus.h (revision 27864)
+++ scribus/scribus.h (working copy)
@@ -450,6 +450,7 @@
*/
void deletePage(int from, int to);
void deletePage2(int pg);
+ void deleteMasterPage(const QString& masterPageName);
/** \brief Verschiebt Seiten */
void movePage();
void copyPage();
Index: scribus/scribusdoc.cpp
===================================================================
--- scribus/scribusdoc.cpp (revision 27864)
+++ scribus/scribusdoc.cpp (working copy)
@@ -2801,6 +2801,23 @@
}
+QPair<ScPage*, ScPage*> ScribusDoc::addMasterSpread(int pageNumber, const QString& pageName)
+{
+ UndoTransaction activeTransaction;
+ if (UndoManager::undoEnabled())
+ activeTransaction = m_undoManager->beginTransaction(getUName(), Um::IDocument, Um::NewMasterPage, pageName, Um::ICreate);
+
+ const QUuid masterId = QUuid::createUuid();
+ ScPage* leftPage = addMasterPage(pageNumber, pageName, masterId, MasterPageSide::Left);
+ ScPage* rightPage = addMasterPage(pageNumber + 1, pageName, masterId, MasterPageSide::Right);
+
+ if (activeTransaction)
+ activeTransaction.commit();
+
+ return qMakePair(leftPage, rightPage);
+}
+
+
bool ScribusDoc::renameMasterPage(const QString& oldPageName, const QString& newPageName)
{
if (!MasterNames.contains(oldPageName))
@@ -2962,47 +2979,57 @@
}
+bool ScribusDoc::isMasterItemOnCurrentMaster(const PageItem* item) const
+{
+ if (!item || !m_currentPage)
+ return false;
+
+ const QUuid currentMasterId = m_currentPage->masterPageId();
+ if (!currentMasterId.isNull() && !item->masterPageId().isNull())
+ return item->masterPageId() == currentMasterId;
+
+ return item->OnMasterPage == m_currentPage->pageName();
+}
+
+
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())
+ for (int pageIndex = 0; pageIndex < DocPages.count(); ++pageIndex)
{
- docPage = dpIt.next();
- if (docPage->masterPageName() == oldMasterPage)
+ ScPage* docPage = DocPages.at(pageIndex);
+ if (docPage->masterPageName() != oldMasterPage)
+ continue;
+
+ QString replacementName;
+ const PageLocation pageLoc = locationOfPage(pageIndex);
+ if (pageLoc == LeftPage && MasterNames.contains(CommonStrings::trMasterPageNormalLeft)
+ && CommonStrings::trMasterPageNormalLeft != oldMasterPage)
+ replacementName = CommonStrings::trMasterPageNormalLeft;
+ else if (pageLoc == RightPage && MasterNames.contains(CommonStrings::trMasterPageNormalRight)
+ && CommonStrings::trMasterPageNormalRight != oldMasterPage)
+ replacementName = CommonStrings::trMasterPageNormalRight;
+ else if (pageLoc == MiddlePage && MasterNames.contains(CommonStrings::trMasterPageNormalMiddle)
+ && CommonStrings::trMasterPageNormalMiddle != oldMasterPage)
+ replacementName = CommonStrings::trMasterPageNormalMiddle;
+ else if (MasterNames.contains(CommonStrings::trMasterPageNormal)
+ && CommonStrings::trMasterPageNormal != oldMasterPage)
+ replacementName = CommonStrings::trMasterPageNormal;
+
+ if (replacementName.isEmpty())
{
- 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)
+ for (auto it = MasterNames.cbegin(); it != MasterNames.cend(); ++it)
{
- 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());
+ if (it.key() != oldMasterPage)
+ {
+ replacementName = it.key();
+ break;
+ }
}
}
- pageIndex++;
+
+ const QUuid replacementId = masterPageId(replacementName);
+ if (!replacementId.isNull())
+ applyMasterPage(replacementId, pageIndex);
}
}
@@ -5170,6 +5197,17 @@
if (pageNumber == -1 || m_currentPage == nullptr)
return false;
+ // A true-spread master half has an explicit, stable side. Keep the legacy
+ // LeftPg mirror in sync instead of allowing Page Properties or Undo/Redo to
+ // turn a Left half into a Right legacy page (or vice versa).
+ if (masterPageMode())
+ {
+ if (m_currentPage->masterPageSide() == MasterPageSide::Left)
+ pageType = 1;
+ else if (m_currentPage->masterPageSide() == MasterPageSide::Right)
+ pageType = 0;
+ }
+
QRectF pagebox(m_currentPage->xOffset(), m_currentPage->yOffset(), qMax( m_currentPage->width(), width), qMax(m_currentPage->height(), height));
if (UndoManager::undoEnabled())
{
@@ -6205,14 +6243,24 @@
int retw = -1;
if (masterPageMode())
{
+ QList<int> pageIndices = masterPageIndices(m_currentPage->masterPageId());
+ if (pageIndices.isEmpty())
+ pageIndices.append(m_currentPage->pageNr());
MarginStruct pageBleeds;
- getBleeds(m_currentPage, pageBleeds);
- int x = static_cast<int>(m_currentPage->xOffset() - pageBleeds.left());
- int y = static_cast<int>(m_currentPage->yOffset() - pageBleeds.top());
- int w = static_cast<int>(m_currentPage->width() + pageBleeds.left() + pageBleeds.right());
- int h = static_cast<int>(m_currentPage->height() + pageBleeds.bottom() + pageBleeds.top());
- if (QRect(x, y, w, h).contains(qRound(x2), qRound(y2)))
- retw = m_currentPage->pageNr();
+ for (int pageIndex : std::as_const(pageIndices))
+ {
+ const ScPage* page = MasterPages.at(pageIndex);
+ getBleeds(page, pageBleeds);
+ int x = static_cast<int>(page->xOffset() - pageBleeds.left());
+ int y = static_cast<int>(page->yOffset() - pageBleeds.top());
+ int w = static_cast<int>(page->width() + pageBleeds.left() + pageBleeds.right());
+ int h = static_cast<int>(page->height() + pageBleeds.bottom() + pageBleeds.top());
+ if (QRect(x, y, w, h).contains(qRound(x2), qRound(y2)))
+ {
+ retw = pageIndex;
+ break;
+ }
+ }
}
else
{
@@ -6249,15 +6297,40 @@
if (masterPageMode())
{
- MarginStruct pageBleeds;
- getBleeds(m_currentPage, pageBleeds);
- double x1 = m_currentPage->xOffset() - pageBleeds.left();
- double y1 = m_currentPage->yOffset() - pageBleeds.top();
- double w1 = m_currentPage->width() + pageBleeds.left() + pageBleeds.right();
- double h1 = m_currentPage->height() + pageBleeds.bottom() + pageBleeds.top();
- QRectF pageRect(x1, y1, w1, h1);
- if (itemRect.intersects(pageRect))
- retw = m_currentPage->pageNr();
+ QUuid logicalMasterId = currItem->masterPageId();
+ if (logicalMasterId.isNull())
+ logicalMasterId = m_currentPage->masterPageId();
+ QList<int> pageIndices = masterPageIndices(logicalMasterId);
+ if (pageIndices.isEmpty())
+ pageIndices.append(m_currentPage->pageNr());
+
+ auto intersectsMasterPage = [this, &itemRect](int pageIndex)
+ {
+ MarginStruct pageBleeds;
+ const ScPage* page = MasterPages.at(pageIndex);
+ getBleeds(page, pageBleeds);
+ const QRectF pageRect(page->xOffset() - pageBleeds.left(),
+ page->yOffset() - pageBleeds.top(),
+ page->width() + pageBleeds.left() + pageBleeds.right(),
+ page->height() + pageBleeds.bottom() + pageBleeds.top());
+ return itemRect.intersects(pageRect);
+ };
+
+ // A crossing master item keeps its physical half while it still intersects
+ // that half. Geometry only chooses a new owner after the old half is left.
+ if (pageIndices.contains(currItem->OwnPage) && intersectsMasterPage(currItem->OwnPage))
+ retw = currItem->OwnPage;
+ else
+ {
+ for (int pageIndex : std::as_const(pageIndices))
+ {
+ if (intersectsMasterPage(pageIndex))
+ {
+ retw = pageIndex;
+ break;
+ }
+ }
+ }
}
else
{
@@ -6475,9 +6548,22 @@
page->setPageNr(i);
if (masterPageMode())
{
- page->setXOffset(m_docPrefsData.displayPrefs.scratch.left());
+ double masterX = m_docPrefsData.displayPrefs.scratch.left();
+ if (page->masterPageSide() == MasterPageSide::Right && isMasterSpread(page->masterPageId()))
+ {
+ const int leftIndex = masterPageIndex(page->masterPageId(), MasterPageSide::Left);
+ if (leftIndex >= 0)
+ masterX += MasterPages.at(leftIndex)->initialWidth();
+ }
+ page->setXOffset(masterX);
page->setYOffset(m_docPrefsData.displayPrefs.scratch.top());
- if (page->LeftPg == 0)
+ const MasterPageSide masterSide = page->masterPageSide();
+ if (masterSide == MasterPageSide::Left)
+ {
+ page->Margins.setLeft(page->initialMargins.right());
+ page->Margins.setRight(page->initialMargins.left());
+ }
+ else if (masterSide == MasterPageSide::Right || page->LeftPg == 0)
{
page->Margins.setRight(page->initialMargins.right());
page->Margins.setLeft(page->initialMargins.left());
@@ -6697,9 +6783,13 @@
PageLocation pageLocation = MiddlePage;
if (page->pageNameEmpty()) // Standard page
pageLocation = locationOfPage(page->pageNr());
- else if (page->LeftPg == 1) // Left Master page
+ else if (page->masterPageSide() == MasterPageSide::Left)
+ pageLocation = LeftPage;
+ else if (page->masterPageSide() == MasterPageSide::Right)
+ pageLocation = RightPage;
+ else if (page->LeftPg == 1) // Legacy Left Master page
pageLocation = LeftPage;
- else if (page->LeftPg == 0) // Right Master page
+ else if (page->LeftPg == 0) // Legacy Right Master page
pageLocation = RightPage;
else // Middle Master page
pageLocation = MiddlePage;
@@ -12126,6 +12216,13 @@
void ScribusDoc::itemSelection_DeleteItem(Selection* customSelection, bool forceDeletion)
{
+ itemSelection_DeleteItem(customSelection, forceDeletion, ItemDeletionSelectionPolicy::Restore, ItemDeletionOrderPolicy::OriginalIndex);
+}
+
+void ScribusDoc::itemSelection_DeleteItem(Selection* customSelection, bool forceDeletion, ItemDeletionSelectionPolicy selectionPolicy, ItemDeletionOrderPolicy orderPolicy)
+{
+ const bool restoreSelection = (selectionPolicy == ItemDeletionSelectionPolicy::Restore);
+ const bool stableItemOrder = (orderPolicy == ItemDeletionOrderPolicy::StableNeighbors);
if (appMode == modeEditClip)
return;
Selection* itemSelection = (customSelection != nullptr) ? customSelection : m_Selection;
@@ -12255,8 +12352,18 @@
auto *is = new ScItemState< QList<PageItem*> >(Um::Delete + " " + currItem->getUName(), "", Um::IDelete);
is->setItem(delItems);
is->set("DELETE_ITEM");
- is->set("ITEMID", itemList->indexOf(currItem));
+ const int itemIndex = itemList->indexOf(currItem);
+ is->set("ITEMID", itemIndex);
is->set("ID", selectedItemCount - (i + 1));
+ is->set("RESTORE_SELECTION", restoreSelection);
+ is->set("STABLE_ITEM_ORDER", stableItemOrder);
+ if (stableItemOrder)
+ {
+ if (itemIndex > 0)
+ is->set("PREV_ITEM_UID", static_cast<quint64>(itemList->at(itemIndex - 1)->getUId()));
+ if (itemIndex + 1 < itemList->count())
+ is->set("NEXT_ITEM_UID", static_cast<quint64>(itemList->at(itemIndex + 1)->getUId()));
+ }
m_undoManager->action(Pages->at(0), is, currItem->getUPixmap());
}
itemList->removeAll(currItem);
@@ -17400,6 +17507,11 @@
void ScribusDoc::setNewPrefs(const ApplicationPrefs& prefsData, const ApplicationPrefs& oldPrefsData, bool resizePages, bool resizeMasterPages, bool resizePageMargins, bool resizeMasterPageMargins)
{
+ QList<QPointF> oldMasterOffsets;
+ oldMasterOffsets.reserve(MasterPages.count());
+ for (const ScPage* masterPage : std::as_const(MasterPages))
+ oldMasterOffsets.append(QPointF(masterPage->xOffset(), masterPage->yOffset()));
+
m_docPrefsData = prefsData;
double topDisplacement = prefsData.displayPrefs.scratch.top() - oldPrefsData.displayPrefs.scratch.top();
double leftDisplacement = prefsData.displayPrefs.scratch.left() - oldPrefsData.displayPrefs.scratch.left();
@@ -17409,7 +17521,15 @@
for (int i = 0; i < docItemsCount; ++i)
{
PageItem *item = MasterItems.at(i);
- item->moveBy(leftDisplacement, topDisplacement);
+ double xDisplacement = leftDisplacement;
+ double yDisplacement = topDisplacement;
+ if (item->OwnPage >= 0 && item->OwnPage < MasterPages.count() && item->OwnPage < oldMasterOffsets.count())
+ {
+ const ScPage* masterPage = MasterPages.at(item->OwnPage);
+ xDisplacement = masterPage->xOffset() - oldMasterOffsets.at(item->OwnPage).x();
+ yDisplacement = masterPage->yOffset() - oldMasterOffsets.at(item->OwnPage).y();
+ }
+ item->moveBy(xDisplacement, yDisplacement);
item->setRedrawBounding();
}
@@ -17570,7 +17690,14 @@
pp->initialMargins = m_docPrefsData.docSetupPrefs.margins;
pp->marginPreset = m_docPrefsData.docSetupPrefs.marginPreset;
}
- pp->setXOffset(scratch()->left());
+ double masterX = scratch()->left();
+ if (pp->masterPageSide() == MasterPageSide::Right && isMasterSpread(pp->masterPageId()))
+ {
+ const int leftIndex = masterPageIndex(pp->masterPageId(), MasterPageSide::Left);
+ if (leftIndex >= 0)
+ masterX += MasterPages.at(leftIndex)->initialWidth();
+ }
+ pp->setXOffset(masterX);
pp->setYOffset(scratch()->top());
}
}
Index: scribus/scribusdoc.h
===================================================================
--- scribus/scribusdoc.h (revision 27864)
+++ scribus/scribusdoc.h (working copy)
@@ -35,6 +35,7 @@
#include <QMap>
#include <QObject>
#include <QPixmap>
+#include <QPair>
#include <QRectF>
#include <QStringList>
#include <QTimer>
@@ -262,6 +263,7 @@
void deletePage(int);
//! @brief Add a master page with this function, do not use addPage
ScPage* addMasterPage(int, const QString&, const QUuid& masterId = QUuid(), MasterPageSide side = MasterPageSide::Single);
+ QPair<ScPage*, ScPage*> addMasterSpread(int pageNumber, const QString& pageName);
void deleteMasterPage(int);
//! @brief Rebuild master name list
void rebuildMasterNames();
@@ -272,6 +274,7 @@
int masterPageIndex(const QUuid& masterId, MasterPageSide side) const;
bool masterPageHasSide(const QUuid& masterId, MasterPageSide side) const;
bool isMasterSpread(const QUuid& masterId) const;
+ bool isMasterItemOnCurrentMaster(const PageItem* item) const;
//! @brief Replace a master page by default one
void replaceMasterPage(const QString& oldMasterPage);
//! @brief Rename a master page
@@ -1169,11 +1172,24 @@
int columnOfPage(int pageIndex) const;
+ enum class ItemDeletionSelectionPolicy
+ {
+ Restore,
+ DoNotRestore
+ };
+
+ enum class ItemDeletionOrderPolicy
+ {
+ OriginalIndex,
+ StableNeighbors
+ };
+
QList<PageItem*>* groupOfItem(QList<PageItem*>* itemList, PageItem* item);
PageItem* groupObjectsSelection(Selection* customSelection = nullptr);
PageItem* groupObjectsList(QList<PageItem*> &itemList);
void groupObjectsToItem(PageItem* groupItem, QList<PageItem*> &itemList);
PageItem * itemSelection_GroupObjects (bool changeLock, bool lock, Selection* customSelection = nullptr, PageItem_Group* groupItem = nullptr);
+ void itemSelection_DeleteItem(Selection* customSelection, bool forceDeletion, ItemDeletionSelectionPolicy selectionPolicy, ItemDeletionOrderPolicy orderPolicy);
void itemSelection_UnGroupObjects(Selection* customSelection = nullptr);
void addToGroup(PageItem* group, PageItem* item);
void removeFromGroup(PageItem* item);
Index: scribus/scribusview.cpp
===================================================================
--- scribus/scribusview.cpp (revision 27864)
+++ scribus/scribusview.cpp (working copy)
@@ -624,7 +624,7 @@
PageItem* item = m_doc->Items->at(i);
if (item->m_layerID != m_doc->activeLayer())
continue;
- if ((m_doc->masterPageMode()) && (!((item->OwnPage == -1) || (item->OwnPage == m_doc->currentPage()->pageNr()))))
+ if (m_doc->masterPageMode() && !m_doc->isMasterItemOnCurrentMaster(item))
continue;
if (m_canvas->frameHitTest(dropPosDocQ, item) >= Canvas::INSIDE)
{
@@ -733,7 +733,7 @@
PageItem* item = m_doc->Items->at(i);
if (item->m_layerID != m_doc->activeLayer())
continue;
- if ((m_doc->masterPageMode()) && (!((item->OwnPage == -1) || (item->OwnPage == m_doc->currentPage()->pageNr()))))
+ if (m_doc->masterPageMode() && !m_doc->isMasterItemOnCurrentMaster(item))
continue;
if ((m_canvas->frameHitTest(dropPosDocQ, item) >= Canvas::INSIDE) && (item->itemType() == PageItem::Symbol))
{
@@ -2337,7 +2337,11 @@
if (!m_doc->masterPageMode())
this->requestMode(modeNormal);
m_doc->setMasterPageMode(true);
- m_doc->setCurrentPage(m_doc->Pages->at(nr));
+ ScPage* masterPage = m_doc->Pages->at(nr);
+ const int leftIndex = m_doc->masterPageIndex(masterPage->masterPageId(), MasterPageSide::Left);
+ if (leftIndex >= 0)
+ masterPage = m_doc->MasterPages.at(leftIndex);
+ m_doc->setCurrentPage(masterPage);
m_ScMW->pageSelector->setEnabled(false);
updateOn = false;
setZoom();
@@ -2433,11 +2437,31 @@
{
ScLayer layer;
layer.isViewable = false;
- int Nr = m_doc->MasterNames.value(name);
- int clipx = static_cast<int>(m_doc->scratch()->left());
- int clipy = static_cast<int>(m_doc->scratch()->top());
- int clipw = qRound(m_doc->MasterPages.at(Nr)->width());
- int cliph = qRound(m_doc->MasterPages.at(Nr)->height());
+ const QUuid masterId = m_doc->masterPageId(name);
+ QList<int> masterIndices = m_doc->masterPageIndices(masterId);
+ if (masterIndices.isEmpty())
+ return QImage();
+
+ int Nr = m_doc->masterPageIndex(masterId, MasterPageSide::Left);
+ if (Nr < 0)
+ Nr = masterIndices.first();
+ const ScPage* firstMasterPage = m_doc->MasterPages.at(masterIndices.first());
+ double minX = firstMasterPage->xOffset();
+ double minY = firstMasterPage->yOffset();
+ double maxX = firstMasterPage->xOffset() + firstMasterPage->width();
+ double maxY = firstMasterPage->yOffset() + firstMasterPage->height();
+ for (int masterIndex : std::as_const(masterIndices))
+ {
+ const ScPage* masterPage = m_doc->MasterPages.at(masterIndex);
+ minX = qMin(minX, masterPage->xOffset());
+ minY = qMin(minY, masterPage->yOffset());
+ maxX = qMax(maxX, masterPage->xOffset() + masterPage->width());
+ maxY = qMax(maxY, masterPage->yOffset() + masterPage->height());
+ }
+ int clipx = static_cast<int>(std::floor(minX));
+ int clipy = static_cast<int>(std::floor(minY));
+ int clipw = static_cast<int>(std::ceil(maxX)) - clipx;
+ int cliph = static_cast<int>(std::ceil(maxY)) - clipy;
if (clipw <= 0 || cliph <= 0)
return QImage();
@@ -2467,7 +2491,11 @@
{
painter->setPen(Qt::black, 1, Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin);
painter->setBrush(m_doc->paperColor());
- painter->drawRect(clipx, clipy, clipw, cliph);
+ for (int masterIndex : std::as_const(masterIndices))
+ {
+ const ScPage* masterPage = m_doc->MasterPages.at(masterIndex);
+ painter->drawRect(masterPage->xOffset(), masterPage->yOffset(), masterPage->width(), masterPage->height());
+ }
}
painter->beginLayer(1.0, 0);
int layerCount = m_doc->layerCount();
@@ -3412,6 +3440,23 @@
if (obj == widget() && event->type() == QEvent::MouseButtonPress)
{
auto* m = dynamic_cast<QMouseEvent*> (event);
+ if (m_doc->masterPageMode() && m_doc->currentPage())
+ {
+ const auto masterId = m_doc->currentPage()->masterPageId();
+ if (m_doc->isMasterSpread(masterId))
+ {
+ const FPoint mousePoint = m_canvas->globalToCanvas(m->globalPosition());
+ const int pageIndex = m_doc->OnPage(mousePoint.x(), mousePoint.y());
+ if (pageIndex >= 0 && pageIndex < m_doc->MasterPages.count()
+ && m_doc->MasterPages.at(pageIndex)->masterPageId() == masterId
+ && m_doc->currentPage()->pageNr() != pageIndex)
+ {
+ m_doc->setCurrentPage(m_doc->MasterPages.at(pageIndex));
+ setRulerPos(contentsX(), contentsY());
+ m_canvas->update();
+ }
+ }
+ }
bool linkmode = (m_doc->appMode == modeLinkFrames);
firstFrame = m_doc->m_Selection->itemAt(0);
m_canvasMode->mousePressEvent(m);
Index: scribus/ui/mergedoc.cpp
===================================================================
--- scribus/ui/mergedoc.cpp (revision 27864)
+++ scribus/ui/mergedoc.cpp (working copy)
@@ -31,6 +31,8 @@
#include <QToolTip>
#include <QVBoxLayout>
+#include <utility>
+
MergeDoc::MergeDoc(QWidget* parent, bool importMasterPages, int targetDocPageCount, int currentPage) : QDialog(parent)
{
masterPages = importMasterPages;
@@ -158,9 +160,16 @@
importButton->setDefault(true);
if (masterPages)
{
+ m_masterPageNames = masterPageNames;
masterPageNameData->clear();
masterPageNameData->setEnabled(true);
- masterPageNameData->addItems(masterPageNames);
+ QStringList logicalMasterNames;
+ for (const QString& masterName : std::as_const(masterPageNames))
+ {
+ if (!logicalMasterNames.contains(masterName))
+ logicalMasterNames.append(masterName);
+ }
+ masterPageNameData->addItems(logicalMasterNames);
masterPageNameData->setCurrentRow(0);
}
else
@@ -181,6 +190,7 @@
cancelButton->setDefault(true);
if (masterPages)
{
+ m_masterPageNames.clear();
masterPageNameData->clear();
masterPageNameData->setEnabled(false);
}
@@ -230,8 +240,25 @@
QList<int> MergeDoc::getMasterPageIndexes() const
{
QList<int> result;
- for (const auto& row: masterPageNameData->selectionModel()->selectedRows())
- result << row.row();
+ const QList<QList<int>> groups = getMasterPageIndexGroups();
+ for (const QList<int>& group : groups)
+ result.append(group);
+ return result;
+}
+
+QList<QList<int>> MergeDoc::getMasterPageIndexGroups() const
+{
+ QList<QList<int>> result;
+ for (QListWidgetItem* item : masterPageNameData->selectedItems())
+ {
+ QList<int> indices;
+ for (int i = 0; i < m_masterPageNames.count(); ++i)
+ {
+ if (m_masterPageNames.at(i) == item->text())
+ indices.append(i);
+ }
+ result.append(indices);
+ }
return result;
}
Index: scribus/ui/mergedoc.h
===================================================================
--- scribus/ui/mergedoc.h (revision 27864)
+++ scribus/ui/mergedoc.h (working copy)
@@ -12,6 +12,8 @@
#include <QDialog>
#include <QDialogButtonBox>
+#include <QList>
+#include <QStringList>
#include "scribusapi.h"
class QCheckBox;
@@ -38,6 +40,7 @@
QString getFromDoc() const;
QStringList getMasterPageNames() const;
QList<int> getMasterPageIndexes() const;
+ QList<QList<int>> getMasterPageIndexGroups() const;
int getImportWhere() const;
int getImportWherePage() const;
bool getCreatePageChecked() const;
@@ -62,6 +65,7 @@
QGridLayout* fromInfoLayout {nullptr};
int count {0};
bool masterPages {false};
+ QStringList m_masterPageNames;
private slots:
void changeFile();
Index: scribus/ui/newtemp.cpp
===================================================================
--- scribus/ui/newtemp.cpp (revision 27864)
+++ scribus/ui/newtemp.cpp (working copy)
@@ -6,14 +6,18 @@
*/
#include "newtemp.h"
-#include <QPixmap>
-#include <QSpacerItem>
-#include <QHBoxLayout>
-#include <QVBoxLayout>
-#include <QLineEdit>
+#include <QButtonGroup>
#include <QComboBox>
+#include <QFont>
+#include <QGridLayout>
+#include <QHBoxLayout>
#include <QLabel>
+#include <QLineEdit>
#include <QPushButton>
+#include <QSpacerItem>
+#include <QStyle>
+#include <QToolButton>
+#include <QVBoxLayout>
#include "commonstrings.h"
#include "iconmanager.h"
@@ -21,72 +25,201 @@
#include "scpage.h"
#include "scribusdoc.h"
-NewTm::NewTm( QWidget* parent, const QString& text, const QString& title, ScribusDoc *doc, const QString& answerText)
+NewTm::NewTm( QWidget* parent, const QString& text, const QString& title, ScribusDoc *doc, const QString& answerText, bool allowFacingSpread)
: QDialog( parent )
{
setModal(true);
setWindowTitle(title);
setWindowIcon(IconManager::instance().loadIcon("app-icon"));
- QueryLayout = new QVBoxLayout( this );
+ QueryLayout = new QVBoxLayout(this);
QueryLayout->setSpacing(6);
QueryLayout->setContentsMargins(9, 9, 9, 9);
- Layout2 = new QHBoxLayout;
- Layout2->setSpacing(6);
- Layout2->setContentsMargins(0, 0, 0, 0);
- Answer = new QLineEdit( this );
- Frage = new QLabel( text, this );
+
+ int layoutSpacing = style()->pixelMetric(QStyle::PM_LayoutHorizontalSpacing, nullptr, this);
+ if (layoutSpacing < 0)
+ layoutSpacing = QueryLayout->spacing();
+ const int compactSpacing = qMax(1, layoutSpacing / 2);
+ const int fieldSpacing = qMax(layoutSpacing * 2, fontMetrics().height() / 2);
+
+ QFont compactButtonFont(font());
+ if (compactButtonFont.pointSizeF() > 0)
+ compactButtonFont.setPointSizeF(compactButtonFont.pointSizeF() * 0.85);
+ else if (compactButtonFont.pixelSize() > 0)
+ compactButtonFont.setPixelSize(qMax(1, qRound(compactButtonFont.pixelSize() * 0.85)));
+
+ FormLayout = new QGridLayout;
+ FormLayout->setContentsMargins(0, 0, 0, 0);
+ FormLayout->setHorizontalSpacing(layoutSpacing);
+ FormLayout->setVerticalSpacing(fieldSpacing);
+
+ Answer = new QLineEdit(this);
+ Frage = new QLabel(text, this);
Frage->setBuddy(Answer);
- Frage->adjustSize();
- Layout2->addWidget( Frage );
- Layout2->addWidget( Answer );
- QueryLayout->addLayout( Layout2 );
+ FormLayout->addWidget(Frage, 0, 0, Qt::AlignRight | Qt::AlignVCenter);
+ FormLayout->addWidget(Answer, 0, 1);
+
+ const int columns = doc->pageSets()[doc->pagePositioning()].Columns;
+ const bool twoPageFacing = (columns == 2);
- Layout3 = nullptr;
- Links = nullptr;
if (doc->pagePositioning() != singlePage)
{
- Layout3 = new QHBoxLayout;
- Layout3->setSpacing(6);
- Layout3->setContentsMargins(0, 0, 0, 0);
- Links = new QComboBox( this );
- QStringList::Iterator pNames;
- QList<PageSet> pageSet(doc->pageSets());
- for (pNames = pageSet[doc->pagePositioning()].pageNames.begin(); pNames != pageSet[doc->pagePositioning()].pageNames.end(); ++pNames )
+ const QList<PageSet>& pageSet = doc->pageSets();
+ if (twoPageFacing)
{
- //Links->insertItem((*pNames));
- Links->addItem(CommonStrings::translatePageSetLocString((*pNames)));
+ TypeLabel = new QLabel(tr("&Type:"), this);
+ ChoiceLayout = new QHBoxLayout;
+ ChoiceLayout->setSpacing(compactSpacing);
+ ChoiceLayout->setContentsMargins(0, 0, 0, 0);
+
+ TypeButtons = new QButtonGroup(this);
+ TypeButtons->setExclusive(true);
+
+ if (allowFacingSpread)
+ {
+ SpreadButton = new QToolButton(this);
+ SpreadButton->setText(tr("Spread"));
+ SpreadButton->setToolTip(tr("Create a two-page facing master."));
+ SpreadButton->setToolButtonStyle(Qt::ToolButtonTextOnly);
+ SpreadButton->setFont(compactButtonFont);
+ SpreadButton->setCheckable(true);
+ ChoiceLayout->addWidget(SpreadButton);
+ TypeButtons->addButton(SpreadButton, 2);
+ }
+
+ LeftButton = new QToolButton(this);
+ LeftButton->setText(tr("Single Left"));
+ LeftButton->setToolTip(tr("Create a single-page master for left-hand pages."));
+ LeftButton->setToolButtonStyle(Qt::ToolButtonTextOnly);
+ LeftButton->setFont(compactButtonFont);
+ LeftButton->setCheckable(true);
+ ChoiceLayout->addWidget(LeftButton);
+ TypeButtons->addButton(LeftButton, 0);
+
+ RightButton = new QToolButton(this);
+ RightButton->setText(tr("Single Right"));
+ RightButton->setToolTip(tr("Create a single-page master for right-hand pages."));
+ RightButton->setToolButtonStyle(Qt::ToolButtonTextOnly);
+ RightButton->setFont(compactButtonFont);
+ RightButton->setCheckable(true);
+ ChoiceLayout->addWidget(RightButton);
+ TypeButtons->addButton(RightButton, 1);
+ ChoiceLayout->addStretch(1);
+
+ if (doc->currentPage()->LeftPg == 1)
+ LeftButton->setChecked(true);
+ else
+ RightButton->setChecked(true);
+
+ TypeLabel->setBuddy(SpreadButton ? SpreadButton : LeftButton);
+ FormLayout->addWidget(TypeLabel, 1, 0, Qt::AlignRight | Qt::AlignVCenter);
+ FormLayout->addLayout(ChoiceLayout, 1, 1);
}
- if (doc->currentPage()->LeftPg == 1)
- Links->setCurrentIndex(0);
- else if (doc->currentPage()->LeftPg == 0)
- Links->setCurrentIndex(Links->count()-1);
else
- Links->setCurrentIndex(doc->currentPage()->LeftPg-1);
- Links->setEditable(false);
- Layout3->addWidget( Links );
- QueryLayout->addLayout( Layout3 );
+ {
+ SideLabel = new QLabel(tr("&Page side:"), this);
+ Links = new QComboBox(this);
+ SideLabel->setBuddy(Links);
+ for (auto pNames = pageSet[doc->pagePositioning()].pageNames.cbegin(); pNames != pageSet[doc->pagePositioning()].pageNames.cend(); ++pNames)
+ Links->addItem(CommonStrings::translatePageSetLocString((*pNames)));
+ if (doc->currentPage()->LeftPg == 1)
+ Links->setCurrentIndex(0);
+ else if (doc->currentPage()->LeftPg == 0)
+ Links->setCurrentIndex(Links->count()-1);
+ else
+ Links->setCurrentIndex(doc->currentPage()->LeftPg-1);
+ Links->setEditable(false);
+ FormLayout->addWidget(SideLabel, 1, 0, Qt::AlignRight | Qt::AlignVCenter);
+ FormLayout->addWidget(Links, 1, 1);
+ }
}
+
+ // Keep the form labels on one visual grid so their colons line up exactly.
+ QLabel* secondRowLabel = TypeLabel ? TypeLabel : SideLabel;
+ if (secondRowLabel)
+ {
+ const int labelWidth = qMax(Frage->sizeHint().width(), secondRowLabel->sizeHint().width());
+ Frage->setMinimumWidth(labelWidth);
+ Frage->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
+ secondRowLabel->setMinimumWidth(labelWidth);
+ secondRowLabel->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
+ }
+
+ QueryLayout->addLayout(FormLayout);
+ // Keep the top form together, but give it clear separation from the
+ // action row. Extra dialog height is absorbed below this fixed gap.
+ const int actionSpacing = qMax(fieldSpacing * 2, fontMetrics().height());
+ QueryLayout->addSpacing(actionSpacing);
+ QueryLayout->addStretch(1);
+
Layout1 = new QHBoxLayout;
Layout1->setSpacing(6);
Layout1->setContentsMargins(0, 0, 0, 0);
- QSpacerItem* spacer = new QSpacerItem( 2, 2, QSizePolicy::Expanding, QSizePolicy::Minimum );
- Layout1->addItem( spacer );
- PushButton1 = new QPushButton( CommonStrings::tr_OK, this );
- PushButton1->setDefault( true );
- Layout1->addWidget( PushButton1 );
- PushButton2 = new QPushButton( CommonStrings::tr_Cancel, this );
- Layout1->addWidget( PushButton2 );
- QueryLayout->addLayout( Layout1 );
+ QSpacerItem* spacer = new QSpacerItem(2, 2, QSizePolicy::Expanding, QSizePolicy::Minimum);
+ Layout1->addItem(spacer);
+ PushButton1 = new QPushButton(CommonStrings::tr_OK, this);
+ PushButton1->setDefault(true);
+ Layout1->addWidget(PushButton1);
+ PushButton2 = new QPushButton(CommonStrings::tr_Cancel, this);
+ Layout1->addWidget(PushButton2);
+ QueryLayout->addLayout(Layout1);
+
if (!answerText.isEmpty())
{
Answer->setText(answerText);
- Answer->setMinimumWidth(sizeHint().width());
Answer->selectAll();
}
- setMinimumSize(sizeHint());
+
+ // Keep these dialogs compact while still allowing translated labels and
+ // larger application fonts to determine a wider natural size when needed.
+ int answerMinimumWidth = fontMetrics().horizontalAdvance(QLatin1Char('M')) * 19;
+ if (ChoiceLayout)
+ answerMinimumWidth = qMax(answerMinimumWidth, ChoiceLayout->sizeHint().width());
+ else if (Links)
+ answerMinimumWidth = qMax(answerMinimumWidth, Links->sizeHint().width());
+ Answer->setMinimumWidth(qMax(Answer->minimumSizeHint().width(), answerMinimumWidth));
+ QueryLayout->activate();
+ adjustSize();
+ setMinimumWidth(sizeHint().width());
Answer->setFocus();
// signals and slots connections
- connect( PushButton1, SIGNAL( clicked() ), this, SLOT( accept() ) );
- connect( PushButton2, SIGNAL( clicked() ), this, SLOT( reject() ) );
+ connect(PushButton1, SIGNAL(clicked()), this, SLOT(accept()));
+ connect(PushButton2, SIGNAL(clicked()), this, SLOT(reject()));
+}
+
+
+bool NewTm::facingPages() const
+{
+ return TypeButtons && TypeButtons->checkedId() == 2;
+}
+
+int NewTm::pageSideIndex() const
+{
+ if (TypeButtons)
+ {
+ const int index = TypeButtons->checkedId();
+ return (index == 0 || index == 1) ? index : -1;
+ }
+ return Links ? Links->currentIndex() : -1;
+}
+
+int NewTm::pageSideCount() const
+{
+ if (TypeButtons && LeftButton && RightButton)
+ return 2;
+ return Links ? Links->count() : 0;
+}
+
+void NewTm::setPageSideVisible(bool visible)
+{
+ if (LeftButton)
+ LeftButton->setVisible(visible);
+ if (RightButton)
+ RightButton->setVisible(visible);
+ if (TypeLabel && !SpreadButton)
+ TypeLabel->setVisible(visible);
+ if (SideLabel)
+ SideLabel->setVisible(visible);
+ if (Links)
+ Links->setVisible(visible);
}
Index: scribus/ui/newtemp.h
===================================================================
--- scribus/ui/newtemp.h (revision 27864)
+++ scribus/ui/newtemp.h (working copy)
@@ -8,12 +8,15 @@
#define QUERY2_H
#include <QDialog>
-class QHBoxLayout;
-class QVBoxLayout;
-class QLineEdit;
+class QButtonGroup;
class QComboBox;
+class QGridLayout;
+class QHBoxLayout;
class QLabel;
+class QLineEdit;
class QPushButton;
+class QToolButton;
+class QVBoxLayout;
#include "scribusapi.h"
class ScribusDoc;
@@ -23,20 +26,30 @@
Q_OBJECT
public:
- NewTm(QWidget* parent, const QString& text, const QString& title, ScribusDoc* doc, const QString& answerText = QString());
+ NewTm(QWidget* parent, const QString& text, const QString& title, ScribusDoc* doc, const QString& answerText = QString(), bool allowFacingSpread = false);
~NewTm() {};
+ bool facingPages() const;
+ int pageSideIndex() const;
+ int pageSideCount() const;
+ void setPageSideVisible(bool visible);
QPushButton* PushButton1;
QPushButton* PushButton2;
QLineEdit* Answer;
QLabel* Frage;
- QComboBox* Links;
protected:
QVBoxLayout* QueryLayout;
- QHBoxLayout* Layout3;
- QHBoxLayout* Layout2;
+ QGridLayout* FormLayout { nullptr };
+ QHBoxLayout* ChoiceLayout { nullptr };
QHBoxLayout* Layout1;
+ QLabel* TypeLabel { nullptr };
+ QLabel* SideLabel { nullptr };
+ QComboBox* Links { nullptr };
+ QButtonGroup* TypeButtons { nullptr };
+ QToolButton* SpreadButton { nullptr };
+ QToolButton* LeftButton { nullptr };
+ QToolButton* RightButton { nullptr };
};
#endif // QUERY_H
Index: scribus/ui/pagepalette_masterpages.cpp
===================================================================
--- scribus/ui/pagepalette_masterpages.cpp (revision 27864)
+++ scribus/ui/pagepalette_masterpages.cpp (working copy)
@@ -189,12 +189,7 @@
if (m_doc->appMode == modeEditClip)
m_view->requestMode(submodeEndNodeEdit);
- m_doc->scMW()->deletePage2(m_doc->MasterNames[m_currentPage]);
- //<<CB TODO Move back into ScribusDoc::deleteMasterPage();
- //This must happen after the pages have been reformed (view/doc)
- m_doc->rebuildMasterNames();
- // Fix up any pages that refer to the deleted master page
- m_doc->replaceMasterPage(m_currentPage);
+ m_doc->scMW()->deleteMasterPage(m_currentPage);
}
// set the 1st MP for the other slots
@@ -206,8 +201,14 @@
void PagePalette_MasterPages::duplicateMasterPage()
{
+ const QString sourceName = m_currentPage;
+ const QUuid sourceId = m_doc->masterPageId(sourceName);
+ const bool sourceIsSpread = m_doc->isMasterSpread(sourceId);
+
QString name = getUniqueName(m_currentPage, m_doc->MasterNames);
QScopedPointer<NewTm> dia(new NewTm(this, tr("&Name:"), tr("New Master Page"), m_doc, name));
+ if (sourceIsSpread)
+ dia->setPageSideVisible(false);
if (!dia->exec())
return;
@@ -222,37 +223,73 @@
name = getNonReservedName(name);
name = getUniqueName(name, m_doc->MasterNames);
-// PrefsManager& prefsManager = PrefsManager::instance();
- int inde = m_doc->MasterNames.value(m_currentPage);
- int nr = m_doc->Pages->count();
- ScPage* from = m_doc->Pages->at(inde);
- ScPage* destination = m_doc->addMasterPage(nr, name);
- if (m_doc->pagePositioning() != singlePage)
- {
- int lp = dia->Links->currentIndex();
- if (lp == 0)
- lp = 1;
- else if (lp == static_cast<int>(dia->Links->count()-1))
- lp = 0;
- else
- lp++;
- destination->LeftPg = lp;
- }
- destination->initialMargins.setTop(from->initialMargins.top());
- destination->initialMargins.setBottom(from->initialMargins.bottom());
- if (m_doc->pageSets()[m_doc->pagePositioning()].Columns == 1)
+ const int nr = m_doc->Pages->count();
+ ScPage* destination = nullptr;
+ int sourceLeftIndex = -1;
+ int sourceRightIndex = -1;
+ int destinationLeftIndex = -1;
+ int destinationRightIndex = -1;
+
+ if (sourceIsSpread)
{
- destination->initialMargins.setLeft(from->initialMargins.left());
- destination->initialMargins.setRight(from->initialMargins.right());
+ const auto spread = m_doc->addMasterSpread(nr, name);
+ ScPage* destLeft = spread.first;
+ ScPage* destRight = spread.second;
+ sourceLeftIndex = m_doc->masterPageIndex(sourceId, MasterPageSide::Left);
+ sourceRightIndex = m_doc->masterPageIndex(sourceId, MasterPageSide::Right);
+ destinationLeftIndex = destLeft->pageNr();
+ destinationRightIndex = destRight->pageNr();
+ if (sourceLeftIndex >= 0)
+ {
+ const ScPage* sourceLeft = m_doc->MasterPages.at(sourceLeftIndex);
+ destLeft->copySizingProperties(sourceLeft, sourceLeft->Margins);
+ sourceLeft->guides.copy(&destLeft->guides);
+ }
+ if (sourceRightIndex >= 0)
+ {
+ const ScPage* sourceRight = m_doc->MasterPages.at(sourceRightIndex);
+ destRight->copySizingProperties(sourceRight, sourceRight->Margins);
+ sourceRight->guides.copy(&destRight->guides);
+ }
+ destination = destLeft;
}
else
{
- if (destination->LeftPg != from->LeftPg)
+ const int sourceIndex = m_doc->masterPageIndex(sourceId);
+ ScPage* from = m_doc->Pages->at(sourceIndex);
+ destination = m_doc->addMasterPage(nr, name);
+ if (m_doc->pagePositioning() != singlePage)
{
- if (destination->LeftPg > 1)
+ int lp = dia->pageSideIndex();
+ if (lp == 0)
+ lp = 1;
+ else if (lp == dia->pageSideCount()-1)
+ lp = 0;
+ else
+ lp++;
+ destination->LeftPg = lp;
+ }
+ destination->initialMargins.setTop(from->initialMargins.top());
+ destination->initialMargins.setBottom(from->initialMargins.bottom());
+ if (m_doc->pageSets()[m_doc->pagePositioning()].Columns == 1)
+ {
+ destination->initialMargins.setLeft(from->initialMargins.left());
+ destination->initialMargins.setRight(from->initialMargins.right());
+ }
+ else
+ {
+ if (destination->LeftPg != from->LeftPg)
{
- destination->initialMargins.setRight(from->initialMargins.left());
- destination->initialMargins.setLeft(from->initialMargins.left());
+ if (destination->LeftPg > 1)
+ {
+ destination->initialMargins.setRight(from->initialMargins.left());
+ destination->initialMargins.setLeft(from->initialMargins.left());
+ }
+ else
+ {
+ destination->initialMargins.setLeft(from->initialMargins.left());
+ destination->initialMargins.setRight(from->initialMargins.right());
+ }
}
else
{
@@ -260,21 +297,19 @@
destination->initialMargins.setRight(from->initialMargins.right());
}
}
- else
- {
- destination->initialMargins.setLeft(from->initialMargins.left());
- destination->initialMargins.setRight(from->initialMargins.right());
- }
+ from->guides.copy(&destination->guides);
}
- //#8321 : incorrect selection of master page on new mp creation/duplication
- //m_doc->setCurrentPage(destination);
+
+ m_doc->setCurrentPage(destination);
+ m_view->reformPages();
updateMasterPageList(name);
selectMasterPage(name);
+
uint oldItems = m_doc->Items->count();
uint end2 = m_doc->MasterItems.count();
int GrMax = m_doc->GroupCounter;
m_doc->m_Selection->clear();
- if (oldItems>0)
+ if (oldItems > 0)
{
ScLayers::iterator it;
m_doc->m_Selection->delaySignalsOn();
@@ -282,8 +317,10 @@
{
for (uint ite = 0; ite < oldItems; ++ite)
{
- PageItem *itemToCopy = m_doc->Items->at(ite);
- if (itemToCopy->OwnPage == inde && (it->ID == itemToCopy->m_layerID))
+ PageItem* itemToCopy = m_doc->Items->at(ite);
+ const bool sourceItem = (!sourceId.isNull() && itemToCopy->masterPageId() == sourceId)
+ || (itemToCopy->masterPageId().isNull() && itemToCopy->OnMasterPage == sourceName);
+ if (sourceItem && it->ID == itemToCopy->m_layerID)
m_doc->m_Selection->addItem(itemToCopy);
}
if (m_doc->m_Selection->count() != 0)
@@ -297,26 +334,41 @@
m_doc->m_Selection->clear();
m_doc->m_Selection->delaySignalsOff();
}
+
+ const QUuid destinationId = destination->masterPageId();
uint end3 = m_doc->MasterItems.count();
for (uint a = end2; a < end3; ++a)
{
- PageItem *newItem = m_doc->MasterItems.at(a);
- int masterPageIndex = m_doc->MasterNames.value(name);
- newItem->setMasterPage(masterPageIndex, name);
+ PageItem* newItem = m_doc->MasterItems.at(a);
+ const int sourceOwner = newItem->OwnPage;
+ newItem->setMasterPageId(destinationId);
+ newItem->setMasterPageName(name);
+ if (sourceIsSpread && sourceOwner == sourceLeftIndex)
+ newItem->OwnPage = destinationLeftIndex;
+ else if (sourceIsSpread && sourceOwner == sourceRightIndex)
+ newItem->OwnPage = destinationRightIndex;
+ else
+ newItem->OwnPage = m_doc->OnPage(newItem);
}
- from->guides.copy(&destination->guides);
+
m_doc->GroupCounter = GrMax + 1;
m_view->deselectItems(true);
m_doc->setLoading(false);
m_view->reformPages();
m_view->DrawNew();
}
-
void PagePalette_MasterPages::newMasterPage()
{
int nr = m_doc->Pages->count();
+ int masterNumber = 1;
+ QString defaultName;
+ do
+ {
+ defaultName = tr("Master %1").arg(masterNumber++);
+ }
+ while (m_doc->MasterNames.contains(defaultName));
- QScopedPointer<NewTm> dia(new NewTm(this, tr("Name:"), tr("New Master Page"), m_doc, tr("New Master Page %1").arg(nr)));
+ QScopedPointer<NewTm> dia(new NewTm(this, tr("Name:"), tr("New Master Page"), m_doc, defaultName, true));
if (!dia->exec())
return;
@@ -331,25 +383,31 @@
name = getNonReservedName(name);
name = getUniqueName(name, m_doc->MasterNames);
- m_doc->setCurrentPage(m_doc->addMasterPage(nr, name));
- if (m_doc->pagePositioning() != singlePage)
+ if (dia->facingPages())
{
- int lp = dia->Links->currentIndex();
- if (lp == 0)
- lp = 1;
- else if (lp == static_cast<int>(dia->Links->count()-1))
- lp = 0;
- else
- lp++;
- m_doc->Pages->at(nr)->LeftPg = lp;
+ const auto spread = m_doc->addMasterSpread(nr, name);
+ m_doc->setCurrentPage(spread.first);
+ }
+ else
+ {
+ m_doc->setCurrentPage(m_doc->addMasterPage(nr, name));
+ if (m_doc->pagePositioning() != singlePage)
+ {
+ int lp = dia->pageSideIndex();
+ if (lp == 0)
+ lp = 1;
+ else if (lp == dia->pageSideCount()-1)
+ lp = 0;
+ else
+ lp++;
+ m_doc->Pages->at(nr)->LeftPg = lp;
+ }
}
+
+ m_view->reformPages();
updateMasterPageList(name);
- //#8321 : incorrect selection of master page on new mp creation/duplictation
- //m_view->showMasterPage(m_doc->MasterNames[name]);
selectMasterPage(name);
- m_view->reformPages();
}
-
void PagePalette_MasterPages::importPage()
{
QScopedPointer<MergeDoc> dia(new MergeDoc(this, true));
@@ -362,22 +420,40 @@
qApp->setOverrideCursor(QCursor(Qt::WaitCursor));
int nr = m_doc->Pages->count();
- auto indexes = dia->getMasterPageIndexes();
+ const QStringList selectedNames = dia->getMasterPageNames();
+ const QList<QList<int>> indexGroups = dia->getMasterPageIndexGroups();
QString lastName;
- for (auto name: dia->getMasterPageNames())
+ for (int selectionIndex = 0; selectionIndex < selectedNames.count(); ++selectionIndex)
{
- name = getUniqueName(name, m_doc->MasterNames);
- m_doc->setCurrentPage(m_doc->addMasterPage(nr, name));
+ QString name = getUniqueName(selectedNames.at(selectionIndex), m_doc->MasterNames);
+ const QList<int> sourceIndices = indexGroups.value(selectionIndex);
+ if (sourceIndices.isEmpty())
+ continue;
- nr++;
- qApp->processEvents();
+ QList<ScPage*> destinationPages;
+ if (sourceIndices.count() == 2)
+ {
+ const auto spread = m_doc->addMasterSpread(nr, name);
+ destinationPages << spread.first << spread.second;
+ nr += 2;
+ }
+ else
+ {
+ destinationPages << m_doc->addMasterPage(nr, name);
+ ++nr;
+ }
- //CB TODO: If we are loading to a new name, we rely on doc->onpage in
- //FileLoader::PasteItem as this call doesn't pass in the new destination page
- m_doc->scMW()->loadPage(dia->getFromDoc(), indexes.first(), true, name);
- qApp->processEvents();
+ for (int sourceOffset = 0; sourceOffset < sourceIndices.count() && sourceOffset < destinationPages.count(); ++sourceOffset)
+ {
+ m_doc->setCurrentPage(destinationPages.at(sourceOffset));
+ qApp->processEvents();
+
+ //CB TODO: If we are loading to a new name, we rely on doc->onpage in
+ //FileLoader::PasteItem as this call doesn't pass in the new destination page
+ m_doc->scMW()->loadPage(dia->getFromDoc(), sourceIndices.at(sourceOffset), true, name);
+ qApp->processEvents();
+ }
- indexes.removeFirst();
lastName = name;
}
@@ -462,6 +538,10 @@
if (it.key() == CommonStrings::masterPageNormal)
mpName = CommonStrings::trMasterPageNormal;
QListWidgetItem* mpItem = new QListWidgetItem(mpName);
+ const QUuid masterId = m_doc->masterPageId(it.key());
+ const bool spread = m_doc->isMasterSpread(masterId);
+ mpItem->setIcon(IconManager::instance().loadIcon(spread ? "page-type-facing" : "page-type-single"));
+ mpItem->setToolTip(spread ? tr("Facing master spread") : tr("One-page master"));
if (!isReservedName(mpName))
mpItem->setFlags(mpItem->flags() |= Qt::ItemIsEditable);
Index: scribus/ui/pagepalette_pages.cpp
===================================================================
--- scribus/ui/pagepalette_pages.cpp (revision 27864)
+++ scribus/ui/pagepalette_pages.cpp (working copy)
@@ -103,19 +103,11 @@
QMessageBox::Yes); // batch default
if (exit == QMessageBox::Yes)
{
- bool oldMPMode = currView->m_doc->masterPageMode();
int storedPageNum = currView->m_doc->currentPageNumber();
int storedViewXCoor = currView->horizontalScrollBar()->value();
int storedViewYCoor = currView->verticalScrollBar()->value();
- currView->m_doc->setMasterPageMode(true);
- currView->m_doc->scMW()->deletePage2(currView->m_doc->MasterNames[tmp]);
- //<<CB TODO Move back into ScribusDoc::deleteMasterPage();
- //This must happen after the pages have been reformed (view/doc)
- currView->m_doc->rebuildMasterNames();
- // Fix up any pages that refer to the deleted master page
- currView->m_doc->replaceMasterPage(tmp);
- currView->m_doc->setMasterPageMode(oldMPMode);
+ currView->m_doc->scMW()->deleteMasterPage(tmp);
currView->m_doc->setModified(true);
currView->m_doc->setCurrentPage(currView->m_doc->DocPages.at(storedPageNum));
Index: scribus/ui/pagepropertiesdialog.cpp
===================================================================
--- scribus/ui/pagepropertiesdialog.cpp (revision 27864)
+++ scribus/ui/pagepropertiesdialog.cpp (working copy)
@@ -93,12 +93,18 @@
}
Links->setEditable(false);
dsGroupBox7Layout->addWidget( Links, 5, 1);
- if (doc->currentPage()->LeftPg == 0)
+ const MasterPageSide masterSide = doc->currentPage()->masterPageSide();
+ if (masterSide == MasterPageSide::Left)
+ Links->setCurrentIndex(0);
+ else if (masterSide == MasterPageSide::Right)
+ Links->setCurrentIndex(Links->count() - 1);
+ else if (doc->currentPage()->LeftPg == 0)
Links->setCurrentIndex(Links->count()-1);
else if (doc->currentPage()->LeftPg == 1)
Links->setCurrentIndex(0);
else
Links->setCurrentIndex(doc->currentPage()->LeftPg-1);
+ Links->setEnabled(masterSide == MasterPageSide::Single);
}
dialogLayout->addWidget( dsGroupBox7 );
tsm3-application-reflow-v1.05.patch (31,571 bytes)
Index: scribus/canvas.cpp
===================================================================
--- scribus/canvas.cpp (revision 27864)
+++ scribus/canvas.cpp (working copy)
@@ -408,7 +408,10 @@ PageItem* Canvas::itemUnderCursor(QPointF globalPos, PageItem* itemAbove, bool a
// look for masterpage items first
if (allowMasterItems && !m_doc->masterPageMode() && m_doc->currentPage()->FromMaster.count() != 0)
{
- const ScPage* Mp = m_doc->MasterPages.at(m_doc->MasterNames.value(m_doc->currentPage()->masterPageName()));
+ const int masterIndex = m_doc->appliedMasterPageIndex(m_doc->currentPage());
+ if (masterIndex < 0)
+ return nullptr;
+ const ScPage* Mp = m_doc->MasterPages.at(masterIndex);
// if itemAbove is given, we expect to find it among the masterpage items of this page
int currNr = itemAbove ? m_doc->currentPage()->FromMaster.indexOf(itemAbove) - 1 : m_doc->currentPage()->FromMaster.count() - 1;
if (currNr < 0)
@@ -1331,7 +1334,10 @@ void Canvas::DrawMasterItems(ScPainter *painter, const ScPage *page, const ScLay
qRound(clip.width() / m_viewMode.scale + 0.5), qRound(clip.height() / m_viewMode.scale + 0.5));
PageItem *currItem;
- ScPage* Mp = m_doc->MasterPages.at(m_doc->MasterNames.value(page->masterPageName()));
+ const int masterIndex = m_doc->appliedMasterPageIndex(page);
+ if (masterIndex < 0)
+ return;
+ ScPage* Mp = m_doc->MasterPages.at(masterIndex);
if (((layer.blendMode != 0) || (layer.transparency != 1.0)) && (!layer.outlineMode))
painter->beginLayer(layer.transparency, layer.blendMode);
int pageFromMasterCount = page->FromMaster.count();
Index: scribus/documentchecker.cpp
===================================================================
--- scribus/documentchecker.cpp (revision 27864)
+++ scribus/documentchecker.cpp (working copy)
@@ -115,12 +115,29 @@ void DocumentChecker::checkPages(ScribusDoc *currDoc, const CheckerPrefs& checke
if (checkerSettings.checkAppliedMasterDifferentSide)
{
bool error = false;
- int masterPageNumber = -1, masterPageLocation = -1;
+ int masterPageLocation = -1;
+ MasterPageSide masterSide = MasterPageSide::Single;
PageLocation pageLoc = currDoc->locationOfPage(i);
- masterPageNumber = currDoc->MasterNames.value(currDoc->DocPages[i]->masterPageName(), -1);
+ const int masterPageNumber = currDoc->appliedMasterPageIndex(currDoc->DocPages.at(i));
if (masterPageNumber >= 0)
- masterPageLocation = currDoc->MasterPages[masterPageNumber]->LeftPg;
- if (currDoc->pagePositioning() == singlePage)
+ {
+ const ScPage* masterPage = currDoc->MasterPages.at(masterPageNumber);
+ masterPageLocation = masterPage->LeftPg;
+ masterSide = masterPage->masterPageSide();
+ }
+ const bool explicitMasterSide = masterSide == MasterPageSide::Left || masterSide == MasterPageSide::Right;
+ if (currDoc->pagePositioning() == singlePage && explicitMasterSide)
+ error = false;
+ else if (explicitMasterSide)
+ {
+ if (pageLoc == LeftPage)
+ error = masterSide != MasterPageSide::Left;
+ else if (pageLoc == RightPage)
+ error = masterSide != MasterPageSide::Right;
+ else
+ error = true;
+ }
+ else if (currDoc->pagePositioning() == singlePage)
{
if ((pageLoc != LeftPage) || (masterPageLocation != 0))
error = true;
Index: scribus/scribus.cpp
===================================================================
--- scribus/scribus.cpp (revision 27864)
+++ scribus/scribus.cpp (working copy)
@@ -5287,6 +5287,8 @@ void ScribusMainWindow::slotNewPageP(int wo, const QString& templ)
doc->addPageToSection(wo + 1, where, 1);
}
+ doc->reconcileMasterPageSides();
+ view->reformPages(false);
doc->updateEndnotesFrames();
doc->changed();
updateGUIAfterPagesChanged();
@@ -5419,6 +5421,8 @@ void ScribusMainWindow::addNewPages(int wo, int where, int numPages, double heig
doc->changed();
doc->addPageToAnnotLinks(wot, where, numPages);
doc->addPageToSection(wo, where, numPages);
+ if (!m_deferMasterPageSideReconcile)
+ doc->reconcileMasterPageSides();
doc->reformPages();
doc->updateEndnotesFrames();
updateGUIAfterPagesChanged();
@@ -6228,6 +6232,8 @@ void ScribusMainWindow::deletePage(int from, int to)
auto *ss = new SimpleState(Um::DeletePage, QString(), Um::ICreate);
ss->set("DELETE_PAGE");
ss->set("PAGENR", a + 1);
+ ss->set("DELETE_RANGE_FROM", from);
+ ss->set("DELETE_RANGE_TO", to);
ss->set("PAGENAME", doc->Pages->at(a)->pageName());
ss->set("MASTERPAGE", doc->Pages->at(a)->masterPageName());
ss->set("MASTER_PAGE_ID", doc->Pages->at(a)->masterPageId().toString(QUuid::WithoutBraces));
@@ -6270,6 +6276,11 @@ void ScribusMainWindow::deletePage(int from, int to)
doc->removePageFromSection(a);
}
}
+ if (!doc->masterPageMode() && !m_deferMasterPageSideReconcile)
+ {
+ doc->reconcileMasterPageSides();
+ doc->reformPages();
+ }
pageSelector->setMaximum(doc->Pages->count());
m_undoManager->setUndoEnabled(false); // ugly hack to disable object moving when undoing page deletion
view->reformPagesView();
@@ -7889,6 +7900,17 @@ void ScribusMainWindow::ApplyMasterPage()
return;
QString masterPageName(dia->getMasterPageName());
+ if (dia->applyToSpread())
+ {
+ const QUuid masterId = doc->masterPageId(masterPageName);
+ doc->applyMasterSpread(masterId, doc->currentPageNumber());
+ view->reformPages();
+ view->DrawNew();
+ pagePalette->rebuild();
+ guidePalette->setupPage(false);
+ return;
+ }
+
int pageSelection = dia->getPageSelection(); //0=current, 1=even, 2=odd, 3=all
int startPage, endPage;
@@ -8018,6 +8040,12 @@ void ScribusMainWindow::restoreDeletePage(SimpleState *state, bool isUndo)
QString pageName = state->get("PAGENAME");
bool savedMasterPageMode = state->getBool("MASTER_PAGE_MODE");
bool currMasterPageMode = doc->masterPageMode();
+ const int deleteRangeFrom = state->contains("DELETE_RANGE_FROM") ? state->getInt("DELETE_RANGE_FROM") : pagenr;
+ const int deleteRangeTo = state->contains("DELETE_RANGE_TO") ? state->getInt("DELETE_RANGE_TO") : pagenr;
+ const bool batchStart = isUndo ? (pagenr == deleteRangeFrom) : (pagenr == deleteRangeTo);
+ const bool batchEnd = isUndo ? (pagenr == deleteRangeTo) : (pagenr == deleteRangeFrom);
+ if (!savedMasterPageMode && batchStart)
+ m_deferMasterPageSideReconcile = true;
if (currMasterPageMode != savedMasterPageMode)
doc->setMasterPageMode(savedMasterPageMode);
if (pagenr == 1)
@@ -8088,6 +8116,12 @@ void ScribusMainWindow::restoreDeletePage(SimpleState *state, bool isUndo)
}
if (currMasterPageMode != savedMasterPageMode)
doc->setMasterPageMode(currMasterPageMode);
+ if (!savedMasterPageMode && batchEnd)
+ {
+ m_deferMasterPageSideReconcile = false;
+ doc->reconcileMasterPageSides();
+ doc->reformPages();
+ }
doc->rebuildMasterNames();
if (isUndo && savedMasterPageMode)
editMasterPagesStart(pageName);
Index: scribus/scribus.h
===================================================================
--- scribus/scribus.h (revision 27864)
+++ scribus/scribus.h (working copy)
@@ -662,6 +662,7 @@ private:
//bool m_arrowKeyDown;
/** @brief tells the undo mode */
bool m_objectSpecificUndo { false };
+ bool m_deferMasterPageSideReconcile { false };
//CB: #8212: add overrideMasterPageSizing, however default to true for compatibility with other calls.. for now
void addNewPages(int wo, int where, int numPages, double height, double width, int orient, const QString& siz, bool mov, QStringList* basedOn = 0, bool overrideMasterPageSizing = true);
Index: scribus/scribusdoc.cpp
===================================================================
--- scribus/scribusdoc.cpp (revision 27864)
+++ scribus/scribusdoc.cpp (working copy)
@@ -2978,6 +2978,157 @@ bool ScribusDoc::isMasterSpread(const QUuid& masterId) const
return masterPageHasSide(masterId, MasterPageSide::Left) && masterPageHasSide(masterId, MasterPageSide::Right);
}
+int ScribusDoc::appliedMasterPageIndex(const ScPage* page) const
+{
+ if (!page)
+ return -1;
+
+ const QUuid masterId = page->appliedMasterPageId();
+ if (!masterId.isNull())
+ {
+ int index = masterPageIndex(masterId, page->appliedMasterPageSide());
+ if (index >= 0)
+ return index;
+ if (isMasterSpread(masterId))
+ {
+ const int pageNumber = page->pageNr();
+ const MasterPageSide side = matchingMasterPageSide(masterId, pageNumber);
+ index = masterPageIndex(masterId, side);
+ if (index >= 0)
+ return index;
+ }
+ index = masterPageIndex(masterId);
+ if (index >= 0)
+ return index;
+ }
+
+ auto it = MasterNames.constFind(page->masterPageName());
+ return it == MasterNames.constEnd() ? -1 : it.value();
+}
+
+MasterPageSide ScribusDoc::matchingMasterPageSide(const QUuid& masterId, int pageNumber) const
+{
+ const int masterIndex = masterPageIndex(masterId);
+ if (masterIndex < 0)
+ return MasterPageSide::Single;
+ if (!isMasterSpread(masterId))
+ return MasterPages.at(masterIndex)->masterPageSide();
+
+ if (pageNumber >= 0 && pageNumber < DocPages.count())
+ {
+ const int columns = pageSets()[m_docPrefsData.docSetupPrefs.pagePositioning].Columns;
+ if (columns == 2)
+ {
+ const PageLocation location = locationOfPage(pageNumber);
+ if (location == LeftPage)
+ return MasterPageSide::Left;
+ if (location == RightPage)
+ return MasterPageSide::Right;
+ }
+
+ // Outside a two-page document spread there is no corresponding side to
+ // remap to. Preserve an already assigned side instead of silently flipping it.
+ const ScPage* page = DocPages.at(pageNumber);
+ const QUuid assignedId = page->appliedMasterPageId().isNull() ? masterPageId(page->masterPageName()) : page->appliedMasterPageId();
+ if (assignedId == masterId)
+ {
+ const MasterPageSide currentSide = page->appliedMasterPageSide();
+ if (currentSide == MasterPageSide::Left || currentSide == MasterPageSide::Right)
+ return currentSide;
+ }
+ }
+
+ return MasterPageSide::Left;
+}
+
+bool ScribusDoc::documentSpreadPages(int pageNumber, int& leftPage, int& rightPage) const
+{
+ leftPage = -1;
+ rightPage = -1;
+ if (pageNumber < 0 || pageNumber >= DocPages.count())
+ return false;
+ if (pageSets()[m_docPrefsData.docSetupPrefs.pagePositioning].Columns != 2)
+ return false;
+
+ const bool rtlBinding = m_docPrefsData.docSetupPrefs.bindingDirection == 1;
+ const PageLocation location = locationOfPage(pageNumber);
+ if (location == LeftPage)
+ {
+ leftPage = pageNumber;
+ const int rightCandidate = rtlBinding ? pageNumber - 1 : pageNumber + 1;
+ if (rightCandidate >= 0 && rightCandidate < DocPages.count() && locationOfPage(rightCandidate) == RightPage)
+ rightPage = rightCandidate;
+ }
+ else if (location == RightPage)
+ {
+ rightPage = pageNumber;
+ const int leftCandidate = rtlBinding ? pageNumber + 1 : pageNumber - 1;
+ if (leftCandidate >= 0 && leftCandidate < DocPages.count() && locationOfPage(leftCandidate) == LeftPage)
+ leftPage = leftCandidate;
+ }
+
+ return leftPage >= 0 && rightPage >= 0;
+}
+
+void ScribusDoc::preserveMasterPageMarginsForLayoutChange(int oldPagePositioning)
+{
+ if (oldPagePositioning < 0 || oldPagePositioning >= pageSets().count())
+ return;
+
+ const int oldColumns = pageSets().at(oldPagePositioning).Columns;
+ const int newColumns = pageSets().at(m_docPrefsData.docSetupPrefs.pagePositioning).Columns;
+ if (!((oldColumns == 1 && newColumns == 2) || (oldColumns == 2 && newColumns == 1)))
+ return;
+
+ for (int pageNumber = 0; pageNumber < DocPages.count(); ++pageNumber)
+ {
+ ScPage* page = DocPages.at(pageNumber);
+ QUuid masterId = page->appliedMasterPageId();
+ if (masterId.isNull())
+ masterId = masterPageId(page->masterPageName());
+ if (masterId.isNull() || !isMasterSpread(masterId))
+ continue;
+
+ const MasterPageSide newSide = matchingMasterPageSide(masterId, pageNumber);
+ if (newSide != page->appliedMasterPageSide())
+ continue;
+
+ const double physicalLeft = page->Margins.left();
+ const double physicalRight = page->Margins.right();
+ if (newColumns == 1 || locationOfPage(pageNumber) == RightPage)
+ {
+ page->initialMargins.setLeft(physicalLeft);
+ page->initialMargins.setRight(physicalRight);
+ }
+ else if (locationOfPage(pageNumber) == LeftPage)
+ {
+ page->initialMargins.setLeft(physicalRight);
+ page->initialMargins.setRight(physicalLeft);
+ }
+ }
+}
+
+void ScribusDoc::reconcileMasterPageSides()
+{
+ if (masterPageMode())
+ return;
+
+ for (int pageNumber = 0; pageNumber < DocPages.count(); ++pageNumber)
+ {
+ ScPage* page = DocPages.at(pageNumber);
+ QUuid masterId = page->appliedMasterPageId();
+ if (masterId.isNull())
+ masterId = masterPageId(page->masterPageName());
+ if (masterId.isNull() || !isMasterSpread(masterId))
+ continue;
+
+ const MasterPageSide side = matchingMasterPageSide(masterId, pageNumber);
+ if (side == page->appliedMasterPageSide())
+ continue;
+ applyMasterPageInternal(masterId, side, pageNumber, false);
+ }
+}
+
bool ScribusDoc::isMasterItemOnCurrentMaster(const PageItem* item) const
{
@@ -3056,6 +3207,7 @@ void ScribusDoc::swapPage(int a, int b)
m_undoManager->action(this, ss);
}
Pages->swapItemsAt(a, b);
+ reconcileMasterPageSides();
reformPages();
changed();
}
@@ -3109,6 +3261,7 @@ void ScribusDoc::movePage(int fromPage, int toPage, int dest, int position)
ss->set("PAGE_MOVE_NEWPOS", position);
m_undoManager->action(this, ss);
}
+ reconcileMasterPageSides();
reformPages();
if (m_View && m_ScMW)
{
@@ -4994,14 +5147,21 @@ bool ScribusDoc::applyMasterPage(const QString& pageName, int pageNumber)
bool ScribusDoc::applyMasterPage(const QUuid& masterId, int pageNumber)
{
- const int index = masterPageIndex(masterId);
- if (index < 0)
+ if (masterPageIndex(masterId) < 0)
return false;
- return applyMasterPage(masterId, MasterPages.at(index)->masterPageSide(), pageNumber);
+ return applyMasterPage(masterId, matchingMasterPageSide(masterId, pageNumber), pageNumber);
}
bool ScribusDoc::applyMasterPage(const QUuid& masterId, MasterPageSide side, int pageNumber)
{
+ return applyMasterPageInternal(masterId, side, pageNumber, true);
+}
+
+bool ScribusDoc::applyMasterPageInternal(const QUuid& masterId, MasterPageSide side, int pageNumber, bool recordUndo)
+{
+ if (pageNumber < 0 || pageNumber >= DocPages.count())
+ return false;
+
int MpNr = masterPageIndex(masterId, side);
if (MpNr < 0 && side != MasterPageSide::Single)
MpNr = masterPageIndex(masterId, MasterPageSide::Single);
@@ -5010,7 +5170,7 @@ bool ScribusDoc::applyMasterPage(const QUuid& masterId, MasterPageSide side, int
const MasterPageSide appliedSide = MasterPages.at(MpNr)->masterPageSide();
const QString pageName = MasterPages.at(MpNr)->pageName();
- if (UndoManager::undoEnabled())
+ if (recordUndo && UndoManager::undoEnabled())
{
if (DocPages.at(pageNumber)->appliedMasterPageId() != masterId || DocPages.at(pageNumber)->appliedMasterPageSide() != appliedSide)
{
@@ -5049,17 +5209,37 @@ bool ScribusDoc::applyMasterPage(const QUuid& masterId, MasterPageSide side, int
Ap->initialMargins.setTop(Mp->Margins.top());
Ap->initialMargins.setBottom(Mp->Margins.bottom());
+ const bool explicitMasterSide = appliedSide == MasterPageSide::Left || appliedSide == MasterPageSide::Right;
if (pageSets()[m_docPrefsData.docSetupPrefs.pagePositioning].Columns == 1)
{
- Ap->initialMargins.setLeft(Mp->Margins.left());
- Ap->initialMargins.setRight(Mp->Margins.right());
+ if (explicitMasterSide)
+ {
+ // A true-spread half has a stable side independent of legacy LeftPg.
+ // Preserve the physical appearance of that half on a single page.
+ if (appliedSide == MasterPageSide::Left)
+ {
+ Ap->initialMargins.setLeft(Mp->initialMargins.right());
+ Ap->initialMargins.setRight(Mp->initialMargins.left());
+ }
+ else
+ {
+ Ap->initialMargins.setLeft(Mp->initialMargins.left());
+ Ap->initialMargins.setRight(Mp->initialMargins.right());
+ }
+ }
+ else
+ {
+ Ap->initialMargins.setLeft(Mp->Margins.left());
+ Ap->initialMargins.setRight(Mp->Margins.right());
+ }
}
else
{
+ const bool masterIsLeft = explicitMasterSide ? appliedSide == MasterPageSide::Left : Mp->LeftPg != 0;
PageLocation pageLoc = locationOfPage(pageNumber);
if (pageLoc == LeftPage) //Left hand page
{
- if (Mp->LeftPg != 0)
+ if (masterIsLeft)
{
Ap->initialMargins.setRight(Mp->initialMargins.right());
Ap->initialMargins.setLeft(Mp->initialMargins.left());
@@ -5072,7 +5252,7 @@ bool ScribusDoc::applyMasterPage(const QUuid& masterId, MasterPageSide side, int
}
else if (pageLoc == RightPage) // Right hand page
{
- if (Mp->LeftPg != 0)
+ if (masterIsLeft)
{
Ap->initialMargins.setLeft(Mp->initialMargins.right());
Ap->initialMargins.setRight(Mp->initialMargins.left());
@@ -5098,7 +5278,6 @@ bool ScribusDoc::applyMasterPage(const QUuid& masterId, MasterPageSide side, int
Ap->setOrientation(Mp->orientation());
Ap->setSize(Mp->size());
}
- //TODO make a return false if not possible to apply the master page
if (!isLoading())
{
changed();
@@ -5107,6 +5286,28 @@ bool ScribusDoc::applyMasterPage(const QUuid& masterId, MasterPageSide side, int
return true;
}
+bool ScribusDoc::applyMasterSpread(const QUuid& masterId, int pageNumber)
+{
+ if (!isMasterSpread(masterId))
+ return false;
+
+ int leftPage = -1;
+ int rightPage = -1;
+ if (!documentSpreadPages(pageNumber, leftPage, rightPage))
+ return false;
+
+ UndoTransaction trans;
+ if (UndoManager::undoEnabled())
+ trans = m_undoManager->beginTransaction(QString(), nullptr, Um::ApplyMasterPage, masterPageName(masterId));
+
+ const bool leftApplied = applyMasterPageInternal(masterId, MasterPageSide::Left, leftPage, true);
+ const bool rightApplied = applyMasterPageInternal(masterId, MasterPageSide::Right, rightPage, true);
+
+ if (trans)
+ trans.commit();
+ return leftApplied && rightApplied;
+}
+
void ScribusDoc::restoreMasterPageApplying(SimpleState* ss, bool isUndo)
{
@@ -5150,17 +5351,12 @@ void ScribusDoc::restoreCopyPage(SimpleState* ss, bool isUndo)
if (isUndo)
{
- int destLocation = extPage + 1;
+ int deleteFrom = extPage + 1;
if (whereTo == 0)
- --destLocation;
+ --deleteFrom;
else if (whereTo == 2)
- destLocation = DocPages.count();
- for (int i = 0; i < copyCount; ++i)
- {
- m_ScMW->deletePage(destLocation, destLocation);
- if (whereTo == 2)
- --destLocation;
- }
+ deleteFrom = DocPages.count() - copyCount + 1;
+ m_ScMW->deletePage(deleteFrom, deleteFrom + copyCount - 1);
}
else
{
@@ -5533,16 +5729,11 @@ bool ScribusDoc::copyPageToMasterPage(int pageNumber, int leftPage, int maxLeftP
//Copy the items from our current document page's applied *master* page
if (copyFromAppliedMaster)
{
- if (!sourcePage->masterPageNameEmpty() && MasterNames.contains(sourcePage->masterPageName()))
+ const int pageMasterIndex = appliedMasterPageIndex(sourcePage);
+ if (pageMasterIndex >= 0)
{
- ScPage* pageMaster = nullptr;
- for (int i = 0; i < MasterPages.count(); ++i )
- {
- pageMaster = MasterPages[i];
- if (pageMaster->pageName() == sourcePage->masterPageName())
- break;
- }
- if (Layers.count() != 0 && pageMaster != nullptr)
+ ScPage* pageMaster = MasterPages.at(pageMasterIndex);
+ if (Layers.count() != 0)
{
int currActiveLayer = activeLayer();
for (auto it = Layers.begin(); it != Layers.end(); ++it)
@@ -5551,7 +5742,7 @@ bool ScribusDoc::copyPageToMasterPage(int pageNumber, int leftPage, int maxLeftP
for (int ite = 0; ite < masterItemsOldCount; ++ite)
{
PageItem *itemToCopy = MasterItems.at(ite);
- if ((itemToCopy->OnMasterPage == pageMaster->pageName()) && (it->ID == itemToCopy->m_layerID))
+ if ((itemToCopy->OwnPage == pageMasterIndex) && (it->ID == itemToCopy->m_layerID))
tempSelection.addItem(itemToCopy);
}
if (tempSelection.count() != 0)
@@ -7758,6 +7949,7 @@ void ScribusDoc::copyPage(int pageNumberToCopy, int existingPage, int whereToIns
addPageToAnnotLinks(annotLinksInsert, whereToInsert, copyCount);
addPageToSection(existingPage, whereToInsert, copyCount);
+ reconcileMasterPageSides();
if (lastDest != nullptr)
setCurrentPage(lastDest);
else
@@ -17516,6 +17708,7 @@ void ScribusDoc::setNewPrefs(const ApplicationPrefs& prefsData, const Applicatio
double topDisplacement = prefsData.displayPrefs.scratch.top() - oldPrefsData.displayPrefs.scratch.top();
double leftDisplacement = prefsData.displayPrefs.scratch.left() - oldPrefsData.displayPrefs.scratch.left();
applyPrefsPageSizingAndMargins(resizePages, resizeMasterPages, resizePageMargins, resizeMasterPageMargins);
+ reconcileMasterPageSides();
int docItemsCount = MasterItems.count();
for (int i = 0; i < docItemsCount; ++i)
@@ -17661,15 +17854,18 @@ void ScribusDoc::applyPrefsPageSizingAndMargins(bool resizePages, bool resizeMas
//CB #6796: find the master page (*mp) for the current page (*pp)
//check if *pp's margins are the same as the *mp's current margins
//apply new margins if same
- const int masterPageNumber = MasterNames[pp->masterPageName()];
- const ScPage* mp = MasterPages.at(masterPageNumber);
- if (pp->initialMargins.left() == mp->initialMargins.left() &&
- pp->initialMargins.top() == mp->initialMargins.top() &&
- pp->initialMargins.right() == mp->initialMargins.right() &&
- pp->initialMargins.bottom() == mp->initialMargins.bottom())
+ const int masterPageNumber = appliedMasterPageIndex(pp);
+ if (masterPageNumber >= 0)
{
- pp->initialMargins = m_docPrefsData.docSetupPrefs.margins;
- pp->marginPreset = m_docPrefsData.docSetupPrefs.marginPreset;
+ const ScPage* mp = MasterPages.at(masterPageNumber);
+ if (pp->initialMargins.left() == mp->initialMargins.left() &&
+ pp->initialMargins.top() == mp->initialMargins.top() &&
+ pp->initialMargins.right() == mp->initialMargins.right() &&
+ pp->initialMargins.bottom() == mp->initialMargins.bottom())
+ {
+ pp->initialMargins = m_docPrefsData.docSetupPrefs.margins;
+ pp->marginPreset = m_docPrefsData.docSetupPrefs.marginPreset;
+ }
}
}
}
Index: scribus/scribusdoc.h
===================================================================
--- scribus/scribusdoc.h (revision 27864)
+++ scribus/scribusdoc.h (working copy)
@@ -274,6 +274,11 @@ class SCRIBUS_API ScribusDoc : public QObject, public UndoObject, public Observa
int masterPageIndex(const QUuid& masterId, MasterPageSide side) const;
bool masterPageHasSide(const QUuid& masterId, MasterPageSide side) const;
bool isMasterSpread(const QUuid& masterId) const;
+ int appliedMasterPageIndex(const ScPage* page) const;
+ MasterPageSide matchingMasterPageSide(const QUuid& masterId, int pageNumber) const;
+ bool documentSpreadPages(int pageNumber, int& leftPage, int& rightPage) const;
+ void preserveMasterPageMarginsForLayoutChange(int oldPagePositioning);
+ void reconcileMasterPageSides();
bool isMasterItemOnCurrentMaster(const PageItem* item) const;
//! @brief Replace a master page by default one
void replaceMasterPage(const QString& oldMasterPage);
@@ -847,6 +852,7 @@ class SCRIBUS_API ScribusDoc : public QObject, public UndoObject, public Observa
bool applyMasterPage(const QString& pageName, int pageNumber);
bool applyMasterPage(const QUuid& masterId, int pageNumber);
bool applyMasterPage(const QUuid& masterId, MasterPageSide side, int pageNumber);
+ bool applyMasterSpread(const QUuid& masterId, int pageNumber);
/**
* @brief Undo function for applying a master page
*/
@@ -1378,6 +1384,7 @@ class SCRIBUS_API ScribusDoc : public QObject, public UndoObject, public Observa
void saveFilePermissions(QFileDevice::Permissions p) { m_docFilePermissions = p; }
protected:
+ bool applyMasterPageInternal(const QUuid& masterId, MasterPageSide side, int pageNumber, bool recordUndo);
void addSymbols();
void applyPrefsPageSizingAndMargins(bool resizePages, bool resizeMasterPages, bool resizePageMargins, bool resizeMasterPageMargins);
bool m_hasGUI {false};
Index: scribus/ui/applytemplatedialog.cpp
===================================================================
--- scribus/ui/applytemplatedialog.cpp (revision 27864)
+++ scribus/ui/applytemplatedialog.cpp (working copy)
@@ -79,6 +79,10 @@ ApplyMasterPageDialog::ApplyMasterPageDialog( QWidget* parent ) : QDialog( paren
currentPageRadioButton->setChecked( true );
applyToPageButtonGroupLayout->addWidget( currentPageRadioButton );
+ currentSpreadRadioButton = new QRadioButton(applyToPageButtonGroup);
+ currentSpreadRadioButton->setEnabled(false);
+ applyToPageButtonGroupLayout->addWidget(currentSpreadRadioButton);
+
evenPagesRadioButton = new QRadioButton( applyToPageButtonGroup );
applyToPageButtonGroupLayout->addWidget( evenPagesRadioButton );
@@ -125,9 +129,11 @@ ApplyMasterPageDialog::ApplyMasterPageDialog( QWidget* parent ) : QDialog( paren
// signals and slots connections
connect( useRangeCheckBox, SIGNAL( toggled(bool) ), this, SLOT( enableRange(bool) ) );
connect( currentPageRadioButton, SIGNAL( clicked() ), this, SLOT( singleSelectable() ) );
+ connect( currentSpreadRadioButton, SIGNAL( clicked() ), this, SLOT( singleSelectable() ) );
connect( evenPagesRadioButton, SIGNAL( clicked() ), this, SLOT( rangeSelectable() ) );
connect( oddPagesRadioButton, SIGNAL( clicked() ), this, SLOT( rangeSelectable() ) );
connect( allPagesRadioButton, SIGNAL( clicked() ), this, SLOT( rangeSelectable() ) );
+ connect(masterPageComboBox, &QComboBox::currentIndexChanged, this, &ApplyMasterPageDialog::updateSpreadOption);
connect( fromPageSpinBox, SIGNAL( valueChanged(double) ), this, SLOT( checkRangeFrom() ) );
connect( toPageSpinBox, SIGNAL( valueChanged(double) ), this, SLOT( checkRangeTo() ) );
connect(buttonBox, &QDialogButtonBox::accepted, this, &ApplyMasterPageDialog::accept);
@@ -139,6 +145,7 @@ ApplyMasterPageDialog::ApplyMasterPageDialog( QWidget* parent ) : QDialog( paren
void ApplyMasterPageDialog::setup(ScribusDoc *doc, const QString& Nam)
{
+ m_doc = doc;
QString na = (Nam == CommonStrings::masterPageNormal) ? CommonStrings::trMasterPageNormal : Nam;
QString in;
@@ -158,6 +165,7 @@ void ApplyMasterPageDialog::setup(ScribusDoc *doc, const QString& Nam)
fromPageSpinBox->setValue(doc->currentPage()->pageNr() + 1);
toPageSpinBox->setMaximum(docPagesCount);
toPageSpinBox->setValue(docPagesCount);
+ updateSpreadOption();
}
@@ -168,6 +176,11 @@ QString ApplyMasterPageDialog::getMasterPageName()
}
+bool ApplyMasterPageDialog::applyToSpread() const
+{
+ return currentSpreadRadioButton->isEnabled() && currentSpreadRadioButton->isChecked();
+}
+
int ApplyMasterPageDialog::getPageSelection()
{
if (currentPageRadioButton->isChecked())
@@ -209,6 +222,7 @@ void ApplyMasterPageDialog::rangeSelectable()
{
useRangeCheckBox->setEnabled(true);
enableRange(useRangeCheckBox->isChecked());
+ updateSpreadOption();
}
void ApplyMasterPageDialog::singleSelectable()
@@ -216,6 +230,27 @@ void ApplyMasterPageDialog::singleSelectable()
useRangeCheckBox->setEnabled(false);
fromPageSpinBox->setEnabled(false);
toPageSpinBox->setEnabled(false);
+ updateSpreadOption();
+}
+
+void ApplyMasterPageDialog::updateSpreadOption()
+{
+ bool enableSpreadOption = false;
+ if (m_doc && masterPageComboBox->currentIndex() >= 0)
+ {
+ const QString masterName = masterPageComboBox->currentData().toString();
+ const QUuid masterId = m_doc->masterPageId(masterName);
+ if (m_doc->isMasterSpread(masterId))
+ {
+ int leftPage = -1;
+ int rightPage = -1;
+ enableSpreadOption = m_doc->documentSpreadPages(m_doc->currentPageNumber(), leftPage, rightPage);
+ }
+ }
+
+ currentSpreadRadioButton->setEnabled(enableSpreadOption);
+ if (!enableSpreadOption && currentSpreadRadioButton->isChecked())
+ currentPageRadioButton->setChecked(true);
}
@@ -256,7 +291,9 @@ void ApplyMasterPageDialog::languageChange()
masterPageLabel->setText( tr( "&Master Page:" ) );
applyToPageButtonGroup->setTitle( tr( "Apply to" ) );
currentPageRadioButton->setText( tr( "Current &Page" ) );
+ currentSpreadRadioButton->setText( tr( "Current &Spread" ) );
currentPageRadioButton->setShortcut( QKeySequence( tr( "Alt+P" ) ) );
+ currentSpreadRadioButton->setShortcut( QKeySequence( tr( "Alt+S" ) ) );
evenPagesRadioButton->setText( tr( "&Even Pages" ) );
evenPagesRadioButton->setShortcut( QKeySequence( tr( "Alt+E" ) ) );
oddPagesRadioButton->setText( tr( "O&dd Pages" ) );
Index: scribus/ui/applytemplatedialog.h
===================================================================
--- scribus/ui/applytemplatedialog.h (revision 27864)
+++ scribus/ui/applytemplatedialog.h (working copy)
@@ -47,6 +47,7 @@ public:
QComboBox* masterPageComboBox { nullptr };
QGroupBox* applyToPageButtonGroup { nullptr };
QRadioButton* currentPageRadioButton { nullptr };
+ QRadioButton* currentSpreadRadioButton { nullptr };
QRadioButton* evenPagesRadioButton { nullptr };
QRadioButton* oddPagesRadioButton { nullptr };
QRadioButton* allPagesRadioButton { nullptr };
@@ -61,6 +62,7 @@ public:
virtual bool usingRange();
virtual int getFromPage();
virtual int getToPage();
+ bool applyToSpread() const;
protected:
QVBoxLayout* ApplyMasterPageDialogLayout { nullptr };
@@ -77,12 +79,16 @@ protected slots:
virtual void languageChange();
private slots:
+ void updateSpreadOption();
virtual void checkRangeFrom();
virtual void checkRangeTo();
virtual void enableRange( bool enabled );
virtual void rangeSelectable();
virtual void singleSelectable();
+private:
+ ScribusDoc* m_doc { nullptr };
+
};
#endif // APPLYMASTERPAGEDIALOG_H
Index: scribus/ui/pagepalette_pages.cpp
===================================================================
--- scribus/ui/pagepalette_pages.cpp (revision 27864)
+++ scribus/ui/pagepalette_pages.cpp (working copy)
@@ -301,6 +301,7 @@ void PagePalette_Pages::handlePageLayout(int layout)
{
if (!currView)
return;
+ const int oldPagePositioning = currView->m_doc->pagePositioning();
currView->m_doc->setPagePositioning(layout);
// Block firstPageChanged signal while we sync the UI to the new layout's
@@ -311,6 +312,8 @@ void PagePalette_Pages::handlePageLayout(int layout)
pageLayout->setFirstPage(currView->m_doc->pageSets()[layout].FirstPage);
connect(pageLayout, SIGNAL(firstPageChanged(int)), this, SLOT(handleFirstPage(int)));
+ currView->m_doc->preserveMasterPageMarginsForLayoutChange(oldPagePositioning);
+ currView->m_doc->reconcileMasterPageSides();
currView->reformPages();
currView->DrawNew();
currView->GotoPage(currView->m_doc->currentPageNumber());
@@ -322,6 +325,7 @@ void PagePalette_Pages::handleFirstPage(int fp)
if (!currView)
return;
currView->m_doc->setPageSetFirstPage(currView->m_doc->pagePositioning(), fp);
+ currView->m_doc->reconcileMasterPageSides();
currView->reformPages();
currView->DrawNew();
currView->GotoPage(currView->m_doc->currentPageNumber());
@@ -333,6 +337,7 @@ void PagePalette_Pages::handleBindingDirection(int direction)
if (!currView)
return;
currView->m_doc->setBindingDirection(direction);
+ currView->m_doc->reconcileMasterPageSides();
currView->reformPages();
currView->DrawNew();
currView->GotoPage(currView->m_doc->currentPageNumber());
tsm4-cross-spread-rendering-v1.01.patch (6,100 bytes)
Index: scribus/canvas.cpp
===================================================================
--- scribus/canvas.cpp (revision 27864)
+++ scribus/canvas.cpp (working copy)
@@ -1324,30 +1324,49 @@
return;
if (!layer.isViewable)
return;
- if (page->masterPageNameEmpty())
- return;
- if (page->FromMaster.count() <= 0)
+
+ const QList<PageItem*> masterItems = m_doc->masterItemsForAppliedPage(page);
+ if (masterItems.isEmpty())
return;
FPoint orig = localToCanvas(clip.topLeft());
QRectF cullingArea(static_cast<int>(orig.x()), static_cast<int>(orig.y()),
qRound(clip.width() / m_viewMode.scale + 0.5), qRound(clip.height() / m_viewMode.scale + 0.5));
- PageItem *currItem;
const int masterIndex = m_doc->appliedMasterPageIndex(page);
if (masterIndex < 0)
return;
- ScPage* Mp = m_doc->MasterPages.at(masterIndex);
+ const ScPage* masterPage = m_doc->MasterPages.at(masterIndex);
+
+ const bool clipAtSpine = m_doc->isMasterSpread(masterPage->masterPageId());
+ if (clipAtSpine)
+ {
+ QRectF projectionClip = cullingArea.normalized();
+ if (masterPage->masterPageSide() == MasterPageSide::Left)
+ projectionClip.setRight(qMin(projectionClip.right(), page->xOffset() + page->width()));
+ else if (masterPage->masterPageSide() == MasterPageSide::Right)
+ projectionClip.setLeft(qMax(projectionClip.left(), page->xOffset()));
+
+ if (projectionClip.width() <= 0.0 || projectionClip.height() <= 0.0)
+ return;
+
+ cullingArea = projectionClip;
+ painter->save();
+ painter->newPath();
+ painter->moveTo(cullingArea.left(), cullingArea.top());
+ painter->lineTo(cullingArea.right(), cullingArea.top());
+ painter->lineTo(cullingArea.right(), cullingArea.bottom());
+ painter->lineTo(cullingArea.left(), cullingArea.bottom());
+ painter->closePath();
+ painter->setClipPath();
+ }
+
if (((layer.blendMode != 0) || (layer.transparency != 1.0)) && (!layer.outlineMode))
painter->beginLayer(layer.transparency, layer.blendMode);
- int pageFromMasterCount = page->FromMaster.count();
- for (int a = 0; a < pageFromMasterCount; ++a)
+ for (PageItem* currItem : masterItems)
{
- currItem = page->FromMaster.at(a);
if (currItem->m_layerID != layer.ID)
continue;
- if ((currItem->OwnPage != -1) && (currItem->OwnPage != Mp->pageNr()))
- continue;
if ((m_viewMode.previewMode) && (!currItem->printEnabled()))
continue;
if ((m_viewMode.viewAsPreview) && (!currItem->printEnabled()))
@@ -1359,9 +1378,9 @@
if (!currItem->ChangedMasterItem)
{
//Hack to not check for undo changes, indicate drawing only
- currItem->moveBy(-Mp->xOffset() + page->xOffset(), -Mp->yOffset() + page->yOffset(), true);
- currItem->BoundingX = oldBX - Mp->xOffset() + page->xOffset();
- currItem->BoundingY = oldBY - Mp->yOffset() + page->yOffset();
+ currItem->moveBy(-masterPage->xOffset() + page->xOffset(), -masterPage->yOffset() + page->yOffset(), true);
+ currItem->BoundingX = oldBX - masterPage->xOffset() + page->xOffset();
+ currItem->BoundingY = oldBY - masterPage->yOffset() + page->yOffset();
}
// Save PageItem's OwnPage and set its value to page number
// so that page number placed in text frames can work, also modify
@@ -1413,6 +1432,8 @@
}
if (((layer.blendMode != 0) || (layer.transparency != 1.0)) && (!layer.outlineMode))
painter->endLayer();
+ if (clipAtSpine)
+ painter->restore();
}
Index: scribus/scribusdoc.cpp
===================================================================
--- scribus/scribusdoc.cpp (revision 27864)
+++ scribus/scribusdoc.cpp (working copy)
@@ -3006,6 +3006,30 @@
return it == MasterNames.constEnd() ? -1 : it.value();
}
+QList<PageItem*> ScribusDoc::masterItemsForAppliedPage(const ScPage* page) const
+{
+ QList<PageItem*> items;
+ const int masterIndex = appliedMasterPageIndex(page);
+ if (masterIndex < 0)
+ return items;
+
+ const ScPage* masterPage = MasterPages.at(masterIndex);
+ const QUuid masterId = masterPage->masterPageId();
+ if (masterId.isNull() || !isMasterSpread(masterId))
+ return page->FromMaster;
+
+ // Keep FromMaster owner-based for existing output paths. Canvas projections need
+ // the complete logical spread; the target half is selected by spine clipping.
+ for (PageItem* item : std::as_const(MasterItems))
+ {
+ const bool sameLogicalMaster = (!item->masterPageId().isNull() && item->masterPageId() == masterId)
+ || (item->masterPageId().isNull() && item->OnMasterPage == masterPage->pageName());
+ if (sameLogicalMaster)
+ items.append(item);
+ }
+ return items;
+}
+
MasterPageSide ScribusDoc::matchingMasterPageSide(const QUuid& masterId, int pageNumber) const
{
const int masterIndex = masterPageIndex(masterId);
Index: scribus/scribusdoc.h
===================================================================
--- scribus/scribusdoc.h (revision 27864)
+++ scribus/scribusdoc.h (working copy)
@@ -275,6 +275,7 @@
bool masterPageHasSide(const QUuid& masterId, MasterPageSide side) const;
bool isMasterSpread(const QUuid& masterId) const;
int appliedMasterPageIndex(const ScPage* page) const;
+ QList<PageItem*> masterItemsForAppliedPage(const ScPage* page) const;
MasterPageSide matchingMasterPageSide(const QUuid& masterId, int pageNumber) const;
bool documentSpreadPages(int pageNumber, int& leftPage, int& rightPage) const;
void preserveMasterPageMarginsForLayoutChange(int oldPagePositioning);
Index: scribus/scribusview.cpp
===================================================================
--- scribus/scribusview.cpp (revision 27864)
+++ scribus/scribusview.cpp (working copy)
@@ -2665,9 +2665,9 @@
QList<QPair<PageItem*, int> > changedList;
PageItem* currItem;
- if (!page->FromMaster.isEmpty() && !flags.testFlag(Pixmap_DontReloadImages))
+ if (!flags.testFlag(Pixmap_DontReloadImages))
{
- QList<PageItem*> itemList = page->FromMaster;
+ QList<PageItem*> itemList = m_doc->masterItemsForAppliedPage(page);
while (!itemList.isEmpty())
{
currItem = itemList.takeFirst();
tsm5-output-projection-v1.06.patch (34,208 bytes)
Index: scribus/pdflib_core.cpp
===================================================================
--- scribus/pdflib_core.cpp (revision 27864)
+++ scribus/pdflib_core.cpp (working copy)
@@ -658,7 +658,9 @@
QMap<int, int> pageNsMpa;
for (uint a = 0; a < pageNs.size(); ++a)
{
- pageNsMpa.insert(doc.MasterNames[doc.DocPages.at(pageNs[a] - 1)->masterPageName()], 0);
+ const int masterIndex = doc.appliedMasterPageIndex(doc.DocPages.at(pageNs[a] - 1));
+ if (masterIndex >= 0)
+ pageNsMpa.insert(masterIndex, 0);
}
if (usingGUI)
{
@@ -2577,22 +2579,18 @@
QByteArray tmpOut;
ActPageP = pag;
PageItem* ite;
- QList<PageItem*> PItems;
+ const QList<PageItem*> PItems = doc.masterItemsForMasterPage(pag);
ScLayer ll;
ll.isPrintable = false;
ll.ID = 0;
Content.clear();
- double bLeft, bRight, bBottom, bTop;
- getBleeds(pag, bLeft, bRight, bBottom, bTop);
-
pageData.AObjects.clear();
for (int la = 0; la < doc.Layers.count(); ++la)
{
doc.Layers.levelToLayer(ll, la);
- PItems = doc.MasterItems;
if (!ll.isPrintable && !Options.exportsLayers())
continue;
@@ -2604,21 +2602,10 @@
ite = PItems.at(a);
if (ite->m_layerID != ll.ID)
continue;
- double x = pag->xOffset() - bLeft;
- double y = pag->yOffset() - bTop;
- double w = pag->width() + bLeft + bRight;
- double h1 = pag->height() + bBottom + bTop;
- double ilw= ite->visualLineWidth();
- double x2 = ite->BoundingX - ilw / 2.0;
- double y2 = ite->BoundingY - ilw / 2.0;
- double w2 = ite->BoundingW + ilw;
- double h2 = ite->BoundingH + ilw;
- if (!QRectF(x2, y2, w2, h2).intersects(QRectF(x, y, w, h1)))
+ if (!masterItemIntersectsPage(pag, ite))
continue;
if (ite->ChangedMasterItem)
continue;
- if ((!pag->pageNameEmpty()) && (ite->OwnPage != pag->pageNr()) && (ite->OwnPage != -1))
- continue;
PutPage("q\n");
if ((ite->doOverprint) && (!Options.UseRGB))
{
@@ -3785,38 +3772,52 @@
bool PDFLibCore::PDF_ProcessMasterElements(const ScLayer& layer, const ScPage* pag, uint PNr)
{
- PageItem* ite;
QByteArray content, output;
-// QList<PageItem*> PItems;
- if (pag->masterPageNameEmpty())
+ const int masterIndex = doc.appliedMasterPageIndex(pag);
+ if (masterIndex < 0)
return true;
- if (doc.MasterItems.count() <= 0)
+ const ScPage* masterPage = doc.MasterPages.at(masterIndex);
+ const QList<PageItem*> masterItems = doc.masterItemsForAppliedPage(pag);
+ if (masterItems.isEmpty())
return true;
- const ScPage* mPage = doc.MasterPages.at(doc.MasterNames[doc.DocPages.at(PNr)->masterPageName()]);
- int mPageIndex = doc.MasterPages.indexOf((ScPage* const) mPage) + 1;
if (!Options.MirrorH)
PutPage("1 0 0 1 0 0 cm\n");
if (!layer.isPrintable && !Options.exportsLayers())
return true;
+ const bool clipLogicalSpread = doc.isMasterSpread(masterPage->masterPageId());
+ if (clipLogicalSpread)
+ {
+ double bleedLeft = 0.0;
+ double bleedRight = 0.0;
+ double bleedBottom = 0.0;
+ double bleedTop = 0.0;
+ getBleeds(pag, bleedLeft, bleedRight, bleedBottom, bleedTop);
+ PutPage("q\n");
+ PutPage(FToStr(-bleedLeft) + " " + FToStr(-bleedBottom) + " "
+ + FToStr(pag->width() + bleedLeft + bleedRight) + " "
+ + FToStr(pag->height() + bleedBottom + bleedTop) + " re W n\n");
+ }
+
if (Options.exportsLayers())
PutPage("/OC /" + OCGEntries[layer.Name].Name + " BDC\n");
- for (int i = 0; i < pag->FromMaster.count() && !abortExport; ++i)
+ for (PageItem* item : masterItems)
{
- ite = pag->FromMaster.at(i);
+ if (abortExport)
+ break;
if (usingGUI)
QApplication::processEvents();
- if ((ite->m_layerID != layer.ID) || (!ite->printEnabled()))
+ if ((item->m_layerID != layer.ID) || (!item->printEnabled()))
continue;
- if ((!pag->pageNameEmpty()) && (ite->OwnPage != pag->pageNr()) && (ite->OwnPage != -1))
+ if (!masterItemIntersectsPage(masterPage, item))
continue;
QByteArray name = QByteArray("/master_page_obj_%1_%2")
- .replace("%1", Pdf::toPdf(mPageIndex))
- .replace("%2", Pdf::toPdf(qHash(ite)));
- if (!ite->isTextContainer())
+ .replace("%1", Pdf::toPdf(masterIndex + 1))
+ .replace("%2", Pdf::toPdf(qHash(item)));
+ if (!item->isTextContainer())
{
if (((layer.transparency != 1) || (layer.blendMode != 0)) && Options.supportsTransparency())
content += (name + " Do\n");
@@ -3825,21 +3826,22 @@
continue;
}
- double oldX = ite->xPos();
- double oldY = ite->yPos();
- double oldBX = ite->BoundingX;
- double oldBY = ite->BoundingY;
- ite->setXPos(ite->xPos() - mPage->xOffset() + pag->xOffset(), true);
- ite->setYPos(ite->yPos() - mPage->yOffset() + pag->yOffset(), true);
- if (!PDF_ProcessItem(output, ite, pag, pag->pageNr()))
+ double oldX = item->xPos();
+ double oldY = item->yPos();
+ double oldBX = item->BoundingX;
+ double oldBY = item->BoundingY;
+ item->setXPos(item->xPos() - masterPage->xOffset() + pag->xOffset(), true);
+ item->setYPos(item->yPos() - masterPage->yOffset() + pag->yOffset(), true);
+ const bool processed = PDF_ProcessItem(output, item, pag, pag->pageNr());
+ item->setXYPos(oldX, oldY, true);
+ item->BoundingX = oldBX;
+ item->BoundingY = oldBY;
+ if (!processed)
return false;
if (((layer.transparency != 1) || (layer.blendMode != 0)) && Options.supportsTransparency())
content += output;
else
PutPage(output);
- ite->setXYPos(oldX, oldY, true);
- ite->BoundingX = oldBX;
- ite->BoundingY = oldBY;
}
// Couldn't we use Write_TransparencyGroup() here?
if (((layer.transparency != 1) || (layer.blendMode != 0)) && Options.supportsTransparency())
@@ -3855,9 +3857,9 @@
QByteArray ShName = ResNam + QByteArray::number(ResCount);
ResCount++;
Transpar[ShName] = writeGState("/CA " + FToStr(layer.transparency) + "\n"
- + "/ca " + FToStr(layer.transparency) + "\n"
- + "/SMask /None\n/AIS false\n/OPM 1\n"
- + "/BM /" + blendMode(layer.blendMode) + "\n");
+ + "/ca " + FToStr(layer.transparency) + "\n"
+ + "/SMask /None\n/AIS false\n/OPM 1\n"
+ + "/BM /" + blendMode(layer.blendMode) + "\n");
PdfId formObject = writer.newObject();
writer.startObj(formObject);
PutDoc("<<\n/Type /XObject\n/Subtype /Form\n/FormType 1\n");
@@ -3885,7 +3887,8 @@
}
if (Options.exportsLayers())
PutPage("EMC\n");
-
+ if (clipLogicalSpread)
+ PutPage("Q\n");
return true;
}
@@ -6091,6 +6094,26 @@
return tmp;
}
+bool PDFLibCore::masterItemIntersectsPage(const ScPage* page, const PageItem* item) const
+{
+ double bleedLeft = 0.0;
+ double bleedRight = 0.0;
+ double bleedBottom = 0.0;
+ double bleedTop = 0.0;
+ getBleeds(page, bleedLeft, bleedRight, bleedBottom, bleedTop);
+
+ const QRectF pageRect(page->xOffset() - bleedLeft,
+ page->yOffset() - bleedTop,
+ page->width() + bleedLeft + bleedRight,
+ page->height() + bleedBottom + bleedTop);
+ const double lineWidth = item->visualLineWidth();
+ const QRectF itemRect(item->BoundingX - lineWidth / 2.0,
+ item->BoundingY - lineWidth / 2.0,
+ item->BoundingW + lineWidth,
+ item->BoundingH + lineWidth);
+ return itemRect.intersects(pageRect);
+}
+
void PDFLibCore::getBleeds(const ScPage* page, double &left, double &right) const
{
MarginStruct values;
Index: scribus/pdflib_core.h
===================================================================
--- scribus/pdflib_core.h (revision 27864)
+++ scribus/pdflib_core.h (working copy)
@@ -223,6 +223,7 @@
QByteArray Write_TransparencyGroup(double trans, int blend, QByteArray &data, const PageItem *controlItem = 0);
QByteArray setTextSt(PageItem *ite, uint PNr, const ScPage* pag);
+ bool masterItemIntersectsPage(const ScPage* page, const PageItem* item) const;
void getBleeds(const ScPage* page, double &left, double &right) const;
void getBleeds(const ScPage* page, double &left, double &right, double &bottom, double& top) const;
Index: scribus/plugins/export/svgexplugin/svgexplugin.cpp
===================================================================
--- scribus/plugins/export/svgexplugin/svgexplugin.cpp (revision 27864)
+++ scribus/plugins/export/svgexplugin/svgexplugin.cpp (working copy)
@@ -257,10 +257,11 @@
m_Doc->Layers.levelToLayer(ll, la);
if (ll.isPrintable)
{
- page = m_Doc->MasterPages.at(m_Doc->MasterNames[m_Doc->currentPage()->masterPageName()]);
- processPageLayer(page, ll);
page = m_Doc->currentPage();
- processPageLayer(page, ll);
+ const int masterIndex = m_Doc->appliedMasterPageIndex(page);
+ if (masterIndex >= 0)
+ processPageLayer(m_Doc->MasterPages.at(masterIndex), ll, page);
+ processPageLayer(page, ll, page);
}
}
if(Options.compressFile)
@@ -291,16 +292,15 @@
return true;
}
-void SVGExPlug::processPageLayer(ScPage *page, const ScLayer& layer)
+void SVGExPlug::processPageLayer(ScPage *page, const ScLayer& layer, const ScPage* outputPage)
{
QDomElement layerGroup;
- PageItem *item;
QList<PageItem*> items;
ScPage* SavedAct = m_Doc->currentPage();
if (page->pageNameEmpty())
items = m_Doc->DocItems;
else
- items = m_Doc->MasterItems;
+ items = m_Doc->masterItemsForMasterPage(page);
if (items.isEmpty())
return;
if (!layer.isPrintable)
@@ -313,24 +313,33 @@
layerGroup.setAttribute("inkscape:groupmode", "layer");
if (layer.transparency != 1.0)
layerGroup.setAttribute("opacity", FToStr(layer.transparency));
- for (int j = 0; j < items.count(); ++j)
+
+ // True-spread master items are emitted in target-page coordinates; keep only this physical output page.
+ const bool clipMasterSpread = !page->pageNameEmpty() && m_Doc->isMasterSpread(page->masterPageId());
+ if (clipMasterSpread && outputPage)
+ {
+ const QString clipId = "Clip" + IToStr(m_clipCount++);
+ QDomElement clipPath = m_domDoc.createElement("clipPath");
+ clipPath.setAttribute("id", clipId);
+ clipPath.setAttribute("clipPathUnits", "userSpaceOnUse");
+ QDomElement clipRect = m_domDoc.createElement("rect");
+ clipRect.setAttribute("x", "0");
+ clipRect.setAttribute("y", "0");
+ clipRect.setAttribute("width", FToStr(outputPage->width()));
+ clipRect.setAttribute("height", FToStr(outputPage->height()));
+ clipPath.appendChild(clipRect);
+ m_globalDefs.appendChild(clipPath);
+ layerGroup.setAttribute("clip-path", "url(#" + clipId + ")");
+ }
+
+ const QRectF pageRect(page->xOffset(), page->yOffset(), page->width(), page->height());
+ for (PageItem* item : items)
{
- item = items.at(j);
if (item->m_layerID != layer.ID)
continue;
if (!item->printEnabled())
continue;
- double x = page->xOffset();
- double y = page->yOffset();
- double w = page->width();
- double h = page->height();
- double x2 = item->BoundingX;
- double y2 = item->BoundingY;
- double w2 = item->BoundingW;
- double h2 = item->BoundingH;
- if (!(qMax(x, x2) <= qMin(x + w, x2 + w2) && qMax(y, y2) <= qMin(y + h, y2 + h2)))
- continue;
- if ((!page->pageNameEmpty()) && (item->OwnPage != page->pageNr()) && (item->OwnPage != -1))
+ if (!pageRect.intersects(item->getVisualBoundingRect()))
continue;
processItemOnPage(item->xPos()-page->xOffset(), item->yPos()-page->yOffset(), item, &layerGroup);
}
Index: scribus/plugins/export/svgexplugin/svgexplugin.h
===================================================================
--- scribus/plugins/export/svgexplugin/svgexplugin.h (revision 27864)
+++ scribus/plugins/export/svgexplugin/svgexplugin.h (working copy)
@@ -91,7 +91,7 @@
\brief Process a page to export to SVG format
\param Seite Page *
*/
- void processPageLayer(ScPage *page, const ScLayer& layer);
+ void processPageLayer(ScPage *page, const ScLayer& layer, const ScPage* outputPage);
void processItemOnPage(double xOffset, double yOffset, PageItem *Item, QDomElement *parentElem);
void paintBorder(const TableBorder& border, const QPointF& start, const QPointF& end, const QPointF& startOffsetFactors, const QPointF& endOffsetFactors, QDomElement &ob);
QString processDropShadow(const PageItem *Item);
Index: scribus/plugins/export/xpsexport/xpsexplugin.cpp
===================================================================
--- scribus/plugins/export/xpsexport/xpsexplugin.cpp (revision 27864)
+++ scribus/plugins/export/xpsexport/xpsexplugin.cpp (working copy)
@@ -360,22 +360,22 @@
m_Doc->Layers.levelToLayer(ll, i);
if (ll.isPrintable)
{
- ScPage *mpage = m_Doc->MasterPages.at(m_Doc->MasterNames[Page->masterPageName()]);
- writePageLayer(doc_root, rel_root, mpage, ll);
- writePageLayer(doc_root, rel_root, Page, ll);
+ const int masterIndex = m_Doc->appliedMasterPageIndex(Page);
+ if (masterIndex >= 0)
+ writePageLayer(doc_root, rel_root, m_Doc->MasterPages.at(masterIndex), ll, Page);
+ writePageLayer(doc_root, rel_root, Page, ll, Page);
}
}
}
-void XPSExPlug::writePageLayer(QDomElement &doc_root, QDomElement &rel_root, ScPage *page, ScLayer& layer)
+void XPSExPlug::writePageLayer(QDomElement &doc_root, QDomElement &rel_root, ScPage *page, ScLayer& layer, const ScPage* outputPage)
{
- PageItem *item;
QList<PageItem*> items;
ScPage* SavedAct = m_Doc->currentPage();
if (page->pageNameEmpty())
items = m_Doc->DocItems;
else
- items = m_Doc->MasterItems;
+ items = m_Doc->masterItemsForMasterPage(page);
if (items.count() == 0)
return;
if (!layer.isPrintable)
@@ -384,25 +384,26 @@
QDomElement layerGroup = p_docu.createElement("Canvas");
if (layer.transparency != 1.0)
layerGroup.setAttribute("Opacity", layer.transparency);
- for (int j = 0; j < items.count(); ++j)
+
+ // True-spread master items are emitted in target-page coordinates; keep only this physical output page.
+ const bool clipMasterSpread = !page->pageNameEmpty() && m_Doc->isMasterSpread(page->masterPageId());
+ if (clipMasterSpread && outputPage)
+ {
+ const double clipWidth = outputPage->width() * conversionFactor;
+ const double clipHeight = outputPage->height() * conversionFactor;
+ const QString clipPath = QString("F 1 M0,0 L%1,0 L%1,%2 L0,%2 Z")
+ .arg(FToStr(clipWidth)).arg(FToStr(clipHeight));
+ layerGroup.setAttribute("Clip", clipPath);
+ }
+
+ const QRectF pageRect(page->xOffset(), page->yOffset(), page->width(), page->height());
+ for (PageItem* item : items)
{
- item = items.at(j);
if (item->m_layerID != layer.ID)
continue;
if (!item->printEnabled())
continue;
- double x = page->xOffset();
- double y = page->yOffset();
- double w = page->width();
- double h = page->height();
- double lw = item->visualLineWidth();
- double x2 = item->BoundingX - lw / 2.0;
- double y2 = item->BoundingY - lw / 2.0;
- double w2 = item->BoundingW + lw;
- double h2 = item->BoundingH + lw;
- if (!QRectF(x2, y2, w2, h2).intersects(QRectF(x, y, w, h)))
- continue;
- if ((!page->pageNameEmpty()) && (item->OwnPage != static_cast<int>(page->pageNr())) && (item->OwnPage != -1))
+ if (!pageRect.intersects(item->getVisualBoundingRect()))
continue;
writeItemOnPage(item->xPos() - page->xOffset(), item->yPos() - page->yOffset(), item, layerGroup, rel_root);
}
Index: scribus/plugins/export/xpsexport/xpsexplugin.h
===================================================================
--- scribus/plugins/export/xpsexport/xpsexplugin.h (revision 27864)
+++ scribus/plugins/export/xpsexport/xpsexplugin.h (working copy)
@@ -84,7 +84,7 @@
private:
void writePages(QDomElement &root);
void writePage(QDomElement &doc_root, QDomElement &rel_root, ScPage *Page);
- void writePageLayer(QDomElement &doc_root, QDomElement &rel_root, ScPage *page, ScLayer& layer);
+ void writePageLayer(QDomElement &doc_root, QDomElement &rel_root, ScPage *page, ScLayer& layer, const ScPage* outputPage);
void writeItemOnPage(double xOffset, double yOffset, PageItem *Item, QDomElement &parentElem, QDomElement &rel_root);
void handleImageFallBack(PageItem *Item, QDomElement &parentElem, QDomElement &rel_root);
void processPolyItem(double xOffset, double yOffset, PageItem *Item, QDomElement &parentElem, QDomElement &rel_root);
Index: scribus/pslib.cpp
===================================================================
--- scribus/pslib.cpp (revision 27864)
+++ scribus/pslib.cpp (working copy)
@@ -701,7 +701,9 @@
progressDialog->setProgress("EMP", ap);
QCoreApplication::processEvents();
}
- if (m_Doc->MasterItems.count() <= 0)
+ ScPage* masterPage = m_Doc->MasterPages.at(ap);
+ const QList<PageItem*> masterItems = m_Doc->masterItemsForMasterPage(masterPage);
+ if (masterItems.isEmpty())
continue;
ScLayer ll;
@@ -712,35 +714,23 @@
m_Doc->Layers.levelToLayer(ll, layerLevel);
if (!ll.isPrintable)
continue;
- for (int api = 0; api < m_Doc->MasterItems.count() && !abortExport; ++api)
+ for (PageItem* item : masterItems)
{
- PageItem *it = m_Doc->MasterItems.at(api);
+ if (abortExport)
+ break;
if (progressDialog)
QCoreApplication::processEvents();
- if ((it->m_layerID != ll.ID) || (!it->printEnabled()))
- continue;
- double bLeft, bRight, bBottom, bTop;
- GetBleeds(m_Doc->MasterPages.at(ap), bLeft, bRight, bBottom, bTop);
- double x1 = m_Doc->MasterPages.at(ap)->xOffset() - bLeft;
- double y1 = m_Doc->MasterPages.at(ap)->yOffset() - bTop;
- double w1 = m_Doc->MasterPages.at(ap)->width() + bLeft + bRight;
- double h1 = m_Doc->MasterPages.at(ap)->height()+ bBottom + bTop;
- double lw = it->visualLineWidth();
- double x2 = it->BoundingX - lw / 2.0;
- double y2 = it->BoundingY - lw / 2.0;
- double w2 = qMax(it->BoundingW + lw, 1.0);
- double h2 = qMax(it->BoundingH + lw, 1.0);
- if (!QRectF(x2, y2, w2, h2).intersects(QRectF(x1, y1, w1, h1)))
+ if ((item->m_layerID != ll.ID) || (!item->printEnabled()))
continue;
- if ((it->OwnPage != m_Doc->MasterPages.at(ap)->pageNr()) && (it->OwnPage != -1))
+ if (!masterItemIntersectsPage(masterPage, item))
continue;
- if ((m_optimization == OptimizeSize) && it->isImageFrame() && it->imageIsAvailable && (!it->Pfile.isEmpty()) && it->printEnabled() && (!Options.outputSeparations) && Options.useColor)
+ if ((m_optimization == OptimizeSize) && item->isImageFrame() && item->imageIsAvailable && (!item->Pfile.isEmpty()) && item->printEnabled() && (!Options.outputSeparations) && Options.useColor)
{
- errorOccured = !PS_ImageData(it, it->Pfile, it->itemName(), it->ImageProfile, it->UseEmbedded);
+ errorOccured = !PS_ImageData(item, item->Pfile, item->itemName(), item->ImageProfile, item->UseEmbedded);
if (errorOccured) break;
}
- PS_TemplateStart(QString("mp_obj_%1_%2").arg(ap).arg(qHash(it)));
- ProcessItem(m_Doc->MasterPages.at(ap), it, ap+1, true);
+ PS_TemplateStart(QString("mp_obj_%1_%2").arg(ap).arg(qHash(item)));
+ ProcessItem(masterPage, item, ap+1, true);
PS_TemplateEnd();
}
if (errorOccured) break;
@@ -1761,7 +1751,7 @@
m_Doc->Layers.levelToLayer(ll, lam);
if (!ll.isPrintable)
continue;
- if (!page->masterPageNameEmpty() && !abortExport && !errorOccured)
+ if ((m_Doc->appliedMasterPageIndex(page) >= 0) && !abortExport && !errorOccured)
{
errorOccured |= !ProcessMasterPageLayer(page, ll, a + 1);
}
@@ -2647,97 +2637,128 @@
if (!layer.isPrintable)
return true;
- ScPage* mPage = m_Doc->MasterPages.at(m_Doc->MasterNames.value(page->masterPageName()));
- for (int am = 0; am < page->FromMaster.count() && !abortExport; ++am)
+ const int masterIndex = m_Doc->appliedMasterPageIndex(page);
+ if (masterIndex < 0)
+ return true;
+ ScPage* masterPage = m_Doc->MasterPages.at(masterIndex);
+ const QList<PageItem*> masterItems = m_Doc->masterItemsForAppliedPage(page);
+ if (masterItems.isEmpty())
+ return true;
+
+ const bool clipLogicalSpread = m_Doc->isMasterSpread(masterPage->masterPageId());
+ if (clipLogicalSpread)
+ {
+ double bleedLeft = 0.0;
+ double bleedRight = 0.0;
+ double bleedBottom = 0.0;
+ double bleedTop = 0.0;
+ GetBleeds(page, bleedLeft, bleedRight, bleedBottom, bleedTop);
+ const double clipLeft = -bleedLeft;
+ const double clipRight = page->width() + bleedRight;
+ PS_save();
+ PS_moveto(clipLeft, -bleedBottom);
+ PS_lineto(clipRight, -bleedBottom);
+ PS_lineto(clipRight, page->height() + bleedTop);
+ PS_lineto(clipLeft, page->height() + bleedTop);
+ PS_closepath();
+ PS_clip(false);
+ }
+
+ for (PageItem* item : masterItems)
{
- PageItem *ite = page->FromMaster.at(am);
+ if (abortExport)
+ break;
if (progressDialog)
QCoreApplication::processEvents();
- if ((ite->m_layerID != layer.ID) || (!ite->printEnabled()))
+ if ((item->m_layerID != layer.ID) || (!item->printEnabled()))
continue;
- if (!ite->isTextContainer())
+ if (!item->isTextContainer())
{
- int mpIndex = m_Doc->MasterNames.value(page->masterPageName());
- PS_UseTemplate(QString("mp_obj_%1_%2").arg(mpIndex).arg(qHash(ite)));
+ // Template setup culls items that do not touch this physical master half.
+ // Apply the same test here so a projected spread never references a
+ // template that was intentionally not generated for the target half.
+ if (!masterItemIntersectsPage(masterPage, item))
+ continue;
+ PS_UseTemplate(QString("mp_obj_%1_%2").arg(masterIndex).arg(qHash(item)));
}
- else if (!ite->isTextFrame())
+ else if (!item->isTextFrame())
{
PS_save();
// JG : replace what seems mostly duplicate code by corresponding function call (#3936)
- success &= ProcessItem(mPage, ite, PNr, false, false, true);
+ success &= ProcessItem(masterPage, item, PNr, false, false, true);
PS_restore();
}
- else // if (ite->isTextFrame())
+ else // if (item->isTextFrame())
{
PS_save();
- if (ite->doOverprint)
+ if (item->doOverprint)
{
PutStream("true setoverprint\n");
PutStream("true setoverprintmode\n");
}
- if (ite->fillColor() != CommonStrings::None)
+ if (item->fillColor() != CommonStrings::None)
{
- SetColor(ite->fillColor(), ite->fillShade(), &h, &s, &v, &k);
+ SetColor(item->fillColor(), item->fillShade(), &h, &s, &v, &k);
PS_setcmykcolor_fill(h, s, v, k);
}
- PS_translate(ite->xPos() - mPage->xOffset(), mPage->height() - (ite->yPos() - mPage->yOffset()));
- if (ite->rotation() != 0)
- PS_rotate(-ite->rotation());
- if ((ite->fillColor() != CommonStrings::None) || (ite->GrType != 0))
+ PS_translate(item->xPos() - masterPage->xOffset(), masterPage->height() - (item->yPos() - masterPage->yOffset()));
+ if (item->rotation() != 0)
+ PS_rotate(-item->rotation());
+ if ((item->fillColor() != CommonStrings::None) || (item->GrType != 0))
{
- SetClipPath(ite->PoLine);
+ SetClipPath(item->PoLine);
PS_closepath();
- if (ite->GrType == Gradient_Hatch)
- PS_HatchFill(ite);
- else if (ite->GrType != 0)
- HandleGradientFillStroke(ite, false);
+ if (item->GrType == Gradient_Hatch)
+ PS_HatchFill(item);
+ else if (item->GrType != 0)
+ HandleGradientFillStroke(item, false);
else
- putColor(ite->fillColor(), ite->fillShade(), true);
+ putColor(item->fillColor(), item->fillShade(), true);
}
- if (ite->imageFlippedH())
+ if (item->imageFlippedH())
{
- PS_translate(ite->width(), 0);
+ PS_translate(item->width(), 0);
PS_scale(-1, 1);
}
- if (ite->imageFlippedV())
+ if (item->imageFlippedV())
{
- PS_translate(0, -ite->height());
+ PS_translate(0, -item->height());
PS_scale(1, -1);
}
- if (ite->itemText.length() != 0)
- setTextSt(ite, PNr - 1, mPage, true);
- if ((ite->lineColor() != CommonStrings::None) || (!ite->NamedLStyle.isEmpty()) || (!ite->strokePattern().isEmpty()) || (ite->GrTypeStroke > 0))
- {
- PS_setlinewidth(ite->lineWidth());
- PS_setcapjoin(ite->PLineEnd, ite->PLineJoin);
- PS_setdash(ite->PLineArt, ite->DashOffset, ite->DashValues);
- if (ite->NamedLStyle.isEmpty()) // && (ite->lineWidth() != 0.0))
+ if (item->itemText.length() != 0)
+ setTextSt(item, PNr - 1, masterPage, true);
+ if ((item->lineColor() != CommonStrings::None) || (!item->NamedLStyle.isEmpty()) || (!item->strokePattern().isEmpty()) || (item->GrTypeStroke > 0))
+ {
+ PS_setlinewidth(item->lineWidth());
+ PS_setcapjoin(item->PLineEnd, item->PLineJoin);
+ PS_setdash(item->PLineArt, item->DashOffset, item->DashValues);
+ if (item->NamedLStyle.isEmpty()) // && (item->lineWidth() != 0.0))
{
- const ScPattern* strokePattern = m_Doc->checkedPattern(ite->strokePattern());
- if (strokePattern && (ite->patternStrokePath))
+ const ScPattern* strokePattern = m_Doc->checkedPattern(item->strokePattern());
+ if (strokePattern && (item->patternStrokePath))
{
- QPainterPath path = ite->PoLine.toQPainterPath(false);
- HandleBrushPattern(ite, path, page, PNr, true);
+ QPainterPath path = item->PoLine.toQPainterPath(false);
+ HandleBrushPattern(item, path, page, PNr, true);
}
else
{
- SetClipPath(ite->PoLine);
+ SetClipPath(item->PoLine);
PS_closepath();
if (strokePattern)
- HandleStrokePattern(ite);
- else if (ite->GrTypeStroke > 0)
- HandleGradientFillStroke(ite);
- else if (ite->lineColor() != CommonStrings::None)
+ HandleStrokePattern(item);
+ else if (item->GrTypeStroke > 0)
+ HandleGradientFillStroke(item);
+ else if (item->lineColor() != CommonStrings::None)
{
- SetColor(ite->lineColor(), ite->lineShade(), &h, &s, &v, &k);
+ SetColor(item->lineColor(), item->lineShade(), &h, &s, &v, &k);
PS_setcmykcolor_stroke(h, s, v, k);
- putColor(ite->lineColor(), ite->lineShade(), false);
+ putColor(item->lineColor(), item->lineShade(), false);
}
}
}
else
{
- MultiLine ml = m_Doc->docLineStyles.value(ite->NamedLStyle);
+ MultiLine ml = m_Doc->docLineStyles.value(item->NamedLStyle);
for (int it = ml.size() - 1; it > -1; it--)
{
if (ml[it].Color != CommonStrings::None) //&& (ml[it].Width != 0))
@@ -2747,7 +2768,7 @@
PS_setlinewidth(ml[it].Width);
PS_setcapjoin(static_cast<Qt::PenCapStyle>(ml[it].LineEnd), static_cast<Qt::PenJoinStyle>(ml[it].LineJoin));
PS_setdash(static_cast<Qt::PenStyle>(ml[it].Dash), 0, dum);
- SetClipPath(ite->PoLine);
+ SetClipPath(item->PoLine);
PS_closepath();
putColor(ml[it].Color, ml[it].Shade, false);
}
@@ -2759,6 +2780,9 @@
if (!success)
break;
}
+
+ if (clipLogicalSpread)
+ PS_restore();
return success;
}
@@ -4221,7 +4245,27 @@
}
}
-void PSLib::GetBleeds(ScPage* page, double& left, double& right)
+bool PSLib::masterItemIntersectsPage(const ScPage* page, const PageItem* item)
+{
+ double bleedLeft = 0.0;
+ double bleedRight = 0.0;
+ double bleedBottom = 0.0;
+ double bleedTop = 0.0;
+ GetBleeds(page, bleedLeft, bleedRight, bleedBottom, bleedTop);
+
+ const QRectF pageRect(page->xOffset() - bleedLeft,
+ page->yOffset() - bleedTop,
+ page->width() + bleedLeft + bleedRight,
+ page->height() + bleedBottom + bleedTop);
+ const double lineWidth = item->visualLineWidth();
+ const QRectF itemRect(item->BoundingX - lineWidth / 2.0,
+ item->BoundingY - lineWidth / 2.0,
+ qMax(item->BoundingW + lineWidth, 1.0),
+ qMax(item->BoundingH + lineWidth, 1.0));
+ return itemRect.intersects(pageRect);
+}
+
+void PSLib::GetBleeds(const ScPage* page, double& left, double& right)
{
MarginStruct values;
m_Doc->getBleeds(page, Options.bleeds, values);
@@ -4229,7 +4273,7 @@
right = values.right();
}
-void PSLib::GetBleeds(ScPage* page, double& left, double& right, double& bottom, double& top)
+void PSLib::GetBleeds(const ScPage* page, double& left, double& right, double& bottom, double& top)
{
MarginStruct values;
m_Doc->getBleeds(page, Options.bleeds, values);
Index: scribus/pslib.h
===================================================================
--- scribus/pslib.h (revision 27864)
+++ scribus/pslib.h (working copy)
@@ -137,8 +137,8 @@
virtual void drawArrow(PageItem *ite, QTransform &arrowTrans, int arrowIndex);
virtual void putColor(const QString& color, double shade, bool fill);
virtual void putColorNoDraw(const QString& color, double shade);
- virtual void GetBleeds(ScPage* page, double& left, double& right);
- virtual void GetBleeds(ScPage* page, double& left, double& right, double& bottom, double& top);
+ virtual void GetBleeds(const ScPage* page, double& left, double& right);
+ virtual void GetBleeds(const ScPage* page, double& left, double& right, double& bottom, double& top);
virtual void SetClipPath(const FPointArray &points, bool poly = true);
virtual void SetPathAndClip(const FPointArray &points, bool clipRule);
virtual void HandleBrushPattern(PageItem *item, QPainterPath &path, ScPage* a, uint PNr, bool master);
@@ -162,6 +162,7 @@
bool PutImageDataToStream(const QByteArray& image);
bool PutInterleavedImageMaskToStream(const QByteArray& image, const QByteArray& mask, bool gray);
+ bool masterItemIntersectsPage(const ScPage* page, const PageItem* item);
void WriteASCII85Bytes(const QByteArray& array);
void WriteASCII85Bytes(const unsigned char* array, int length);
Index: scribus/scpageoutput.cpp
===================================================================
--- scribus/scpageoutput.cpp (revision 27864)
+++ scribus/scpageoutput.cpp (working copy)
@@ -101,22 +101,42 @@
void ScPageOutput::drawMasterItems(ScPainterExBase *painter, ScPage *page, const ScLayer& layer, const QRect& clip)
{
- if (page->masterPageNameEmpty())
+ if (!layer.isViewable || !layer.isPrintable)
return;
- if (page->FromMaster.count() <= 0)
+
+ const int masterIndex = m_doc->appliedMasterPageIndex(page);
+ if (masterIndex < 0)
return;
- if (!layer.isViewable || !layer.isPrintable)
+ const ScPage* masterPage = m_doc->MasterPages.at(masterIndex);
+ const QList<PageItem*> masterItems = m_doc->masterItemsForAppliedPage(page);
+ if (masterItems.isEmpty())
return;
- ScPage* masterPage = m_doc->MasterPages.at(m_doc->MasterNames[page->masterPageName()]);
- int pageFromMasterCount = page->FromMaster.count();
- for (int i = 0; i < pageFromMasterCount; ++i)
+ const bool clipAtSpine = m_doc->isMasterSpread(masterPage->masterPageId());
+ if (clipAtSpine)
+ {
+ QRectF projectionClip(QPointF(m_doc->minCanvasCoordinate.x(), m_doc->minCanvasCoordinate.y()),
+ QPointF(m_doc->maxCanvasCoordinate.x(), m_doc->maxCanvasCoordinate.y()));
+ projectionClip = projectionClip.normalized();
+ if (masterPage->masterPageSide() == MasterPageSide::Left)
+ projectionClip.setRight(qMin(projectionClip.right(), page->xOffset() + page->width()));
+ else if (masterPage->masterPageSide() == MasterPageSide::Right)
+ projectionClip.setLeft(qMax(projectionClip.left(), page->xOffset()));
+
+ painter->save();
+ painter->newPath();
+ painter->moveTo(projectionClip.left(), projectionClip.top());
+ painter->lineTo(projectionClip.right(), projectionClip.top());
+ painter->lineTo(projectionClip.right(), projectionClip.bottom());
+ painter->lineTo(projectionClip.left(), projectionClip.bottom());
+ painter->lineTo(projectionClip.left(), projectionClip.top());
+ painter->setClipPath();
+ }
+
+ for (PageItem* currItem : masterItems)
{
- PageItem* currItem = page->FromMaster.at(i);
if (currItem->m_layerID != layer.ID)
continue;
- if ((currItem->OwnPage != -1) && (currItem->OwnPage != masterPage->pageNr()))
- continue;
if (!currItem->printEnabled())
continue;
int savedOwnPage = currItem->OwnPage;
@@ -142,6 +162,9 @@
currItem->BoundingY = OldBY;
}
}
+
+ if (clipAtSpine)
+ painter->restore();
}
void ScPageOutput::drawPageItems(ScPainterExBase *painter, ScPage *page, const ScLayer& layer, const QRect& clip)
Index: scribus/scribusdoc.cpp
===================================================================
--- scribus/scribusdoc.cpp (revision 27864)
+++ scribus/scribusdoc.cpp (working copy)
@@ -3018,13 +3018,29 @@
if (masterId.isNull() || !isMasterSpread(masterId))
return page->FromMaster;
- // Keep FromMaster owner-based for existing output paths. Canvas projections need
- // the complete logical spread; the target half is selected by spine clipping.
+ return masterItemsForMasterPage(masterPage);
+}
+
+QList<PageItem*> ScribusDoc::masterItemsForMasterPage(const ScPage* masterPage) const
+{
+ QList<PageItem*> items;
+ if (!masterPage)
+ return items;
+
+ const QUuid masterId = masterPage->masterPageId();
+ const bool logicalSpread = !masterId.isNull() && isMasterSpread(masterId);
for (PageItem* item : std::as_const(MasterItems))
{
- const bool sameLogicalMaster = (!item->masterPageId().isNull() && item->masterPageId() == masterId)
- || (item->masterPageId().isNull() && item->OnMasterPage == masterPage->pageName());
- if (sameLogicalMaster)
+ if (logicalSpread)
+ {
+ const bool sameLogicalMaster = (!item->masterPageId().isNull() && item->masterPageId() == masterId)
+ || (item->masterPageId().isNull() && item->OnMasterPage == masterPage->pageName());
+ if (sameLogicalMaster)
+ items.append(item);
+ continue;
+ }
+
+ if (item->OwnPage == masterPage->pageNr() || item->OwnPage == -1)
items.append(item);
}
return items;
Index: scribus/scribusdoc.h
===================================================================
--- scribus/scribusdoc.h (revision 27864)
+++ scribus/scribusdoc.h (working copy)
@@ -276,6 +276,8 @@
bool isMasterSpread(const QUuid& masterId) const;
int appliedMasterPageIndex(const ScPage* page) const;
QList<PageItem*> masterItemsForAppliedPage(const ScPage* page) const;
+ //! Returns physical-master items for a normal master, or all items in the logical spread for a true-spread half.
+ QList<PageItem*> masterItemsForMasterPage(const ScPage* masterPage) const;
MasterPageSide matchingMasterPageSide(const QUuid& masterId, int pageNumber) const;
bool documentSpreadPages(int pageNumber, int& leftPage, int& rightPage) const;
void preserveMasterPageMarginsForLayoutChange(int oldPagePositioning);
tsm6-default-master-lifecycle-normal-spread-v1.04.patch (29,413 bytes)
Index: scribus/commonstrings.cpp
===================================================================
--- scribus/commonstrings.cpp (revision 27864)
+++ scribus/commonstrings.cpp (working copy)
@@ -108,6 +108,8 @@
QString CommonStrings:: trMasterPageNormalMiddle;
QString CommonStrings:: masterPageNormalRight;
QString CommonStrings:: trMasterPageNormalRight;
+QString CommonStrings:: masterPageNormalSpread;
+QString CommonStrings:: trMasterPageNormalSpread;
QString CommonStrings::trPenStyle_SolidLine;
QString CommonStrings::trPenStyle_DashedLine;
@@ -381,6 +383,8 @@
CommonStrings::trMasterPageNormalMiddle = tr( "Normal Middle", "Default middle master page" );
CommonStrings::masterPageNormalRight = "Normal Right";
CommonStrings::trMasterPageNormalRight = tr( "Normal Right", "Default right master page" );
+ CommonStrings::masterPageNormalSpread = "Normal Spread";
+ CommonStrings::trMasterPageNormalSpread = tr( "Normal Spread", "Default facing master spread" );
CommonStrings::trPenStyle_SolidLine = tr("Solid Line");
CommonStrings::trPenStyle_DashedLine = tr("Dashed Line");
Index: scribus/commonstrings.h
===================================================================
--- scribus/commonstrings.h (revision 27864)
+++ scribus/commonstrings.h (working copy)
@@ -174,6 +174,8 @@
static QString trMasterPageNormalMiddle;
static QString masterPageNormalRight;
static QString trMasterPageNormalRight;
+ static QString masterPageNormalSpread;
+ static QString trMasterPageNormalSpread;
//Pen Styles
static QString trPenStyle_SolidLine;
Index: scribus/scribus.cpp
===================================================================
--- scribus/scribus.cpp (revision 27864)
+++ scribus/scribus.cpp (working copy)
@@ -5287,7 +5287,7 @@
doc->addPageToSection(wo + 1, where, 1);
}
- doc->reconcileMasterPageSides();
+ doc->reconcileMasterPages();
view->reformPages(false);
doc->updateEndnotesFrames();
doc->changed();
@@ -5422,7 +5422,7 @@
doc->addPageToAnnotLinks(wot, where, numPages);
doc->addPageToSection(wo, where, numPages);
if (!m_deferMasterPageSideReconcile)
- doc->reconcileMasterPageSides();
+ doc->reconcileMasterPages();
doc->reformPages();
doc->updateEndnotesFrames();
updateGUIAfterPagesChanged();
@@ -5478,24 +5478,16 @@
int pageLocation = 0;
copyDialog.values(masterPageName, copyFromMaster, pageLocation);
bool badMasterPageName = doc->MasterNames.contains(masterPageName);
- badMasterPageName |= (masterPageName == CommonStrings::masterPageNormal);
- badMasterPageName |= (masterPageName == CommonStrings::trMasterPageNormal);
- badMasterPageName |= (masterPageName == CommonStrings::trMasterPageNormalLeft);
- badMasterPageName |= (masterPageName == CommonStrings::trMasterPageNormalMiddle);
- badMasterPageName |= (masterPageName == CommonStrings::trMasterPageNormalRight);
- badMasterPageName |= masterPageName.isEmpty();
+ badMasterPageName |= doc->isDefaultMasterPageName(masterPageName);
+ badMasterPageName |= masterPageName.isEmpty();
while (badMasterPageName)
{
if (!copyDialog.exec())
return;
copyDialog.values(masterPageName, copyFromMaster, pageLocation);
badMasterPageName = doc->MasterNames.contains(masterPageName);
- badMasterPageName |= (masterPageName == CommonStrings::masterPageNormal);
- badMasterPageName |= (masterPageName == CommonStrings::trMasterPageNormal);
- badMasterPageName |= (masterPageName == CommonStrings::trMasterPageNormalLeft);
- badMasterPageName |= (masterPageName == CommonStrings::trMasterPageNormalMiddle);
- badMasterPageName |= (masterPageName == CommonStrings::trMasterPageNormalRight);
- badMasterPageName |= masterPageName.isEmpty();
+ badMasterPageName |= doc->isDefaultMasterPageName(masterPageName);
+ badMasterPageName |= masterPageName.isEmpty();
}
int currentPageNumber = doc->currentPage()->pageNr();
bool ok = doc->copyPageToMasterPage(currentPageNumber, pageLocation, pageLocationCount, masterPageName, copyFromMaster);
@@ -6110,7 +6102,7 @@
void ScribusMainWindow::deleteMasterPage(const QString& masterPageName)
{
- if (!HaveDoc)
+ if (!HaveDoc || doc->isDefaultMasterPage(masterPageName))
return;
const QUuid masterId = doc->masterPageId(masterPageName);
@@ -6278,7 +6270,7 @@
}
if (!doc->masterPageMode() && !m_deferMasterPageSideReconcile)
{
- doc->reconcileMasterPageSides();
+ doc->reconcileMasterPages();
doc->reformPages();
}
pageSelector->setMaximum(doc->Pages->count());
@@ -6880,6 +6872,8 @@
view->reformPages();
view->GotoPage(doc->currentPage()->pageNr());
view->DrawNew();
+ if (oldDocPrefs.docSetupPrefs.pagePositioning != newDocPrefs.docSetupPrefs.pagePositioning)
+ pagePalette->updateMasterPageList();
pagePalette->rebuildPages();
emit UpdateRequest(reqCmsOptionsUpdate);
doc->changed();
@@ -8119,7 +8113,7 @@
if (!savedMasterPageMode && batchEnd)
{
m_deferMasterPageSideReconcile = false;
- doc->reconcileMasterPageSides();
+ doc->reconcileMasterPages();
doc->reformPages();
}
doc->rebuildMasterNames();
Index: scribus/scribusdoc.cpp
===================================================================
--- scribus/scribusdoc.cpp (revision 27864)
+++ scribus/scribusdoc.cpp (working copy)
@@ -118,6 +118,102 @@
+namespace
+{
+enum class DefaultMasterRole
+{
+ None,
+ Single,
+ Left,
+ Right,
+ Middle,
+ Spread
+};
+
+DefaultMasterRole defaultMasterRoleForName(const QString& name)
+{
+ if (name == CommonStrings::masterPageNormal || name == CommonStrings::trMasterPageNormal)
+ return DefaultMasterRole::Single;
+ if (name == CommonStrings::masterPageNormalLeft || name == CommonStrings::trMasterPageNormalLeft)
+ return DefaultMasterRole::Left;
+ if (name == CommonStrings::masterPageNormalRight || name == CommonStrings::trMasterPageNormalRight)
+ return DefaultMasterRole::Right;
+ if (name == CommonStrings::masterPageNormalMiddle || name == CommonStrings::trMasterPageNormalMiddle)
+ return DefaultMasterRole::Middle;
+ if (name == CommonStrings::masterPageNormalSpread || name == CommonStrings::trMasterPageNormalSpread)
+ return DefaultMasterRole::Spread;
+ return DefaultMasterRole::None;
+}
+
+QString defaultMasterName(DefaultMasterRole role)
+{
+ switch (role)
+ {
+ case DefaultMasterRole::Single:
+ return CommonStrings::trMasterPageNormal;
+ case DefaultMasterRole::Left:
+ return CommonStrings::trMasterPageNormalLeft;
+ case DefaultMasterRole::Right:
+ return CommonStrings::trMasterPageNormalRight;
+ case DefaultMasterRole::Middle:
+ return CommonStrings::trMasterPageNormalMiddle;
+ case DefaultMasterRole::Spread:
+ return CommonStrings::trMasterPageNormalSpread;
+ case DefaultMasterRole::None:
+ break;
+ }
+ return QString();
+}
+
+QStringList defaultMasterNames(DefaultMasterRole role)
+{
+ QStringList names;
+ const QString translatedName = defaultMasterName(role);
+ if (!translatedName.isEmpty())
+ names.append(translatedName);
+
+ QString canonicalName;
+ switch (role)
+ {
+ case DefaultMasterRole::Single:
+ canonicalName = CommonStrings::masterPageNormal;
+ break;
+ case DefaultMasterRole::Left:
+ canonicalName = CommonStrings::masterPageNormalLeft;
+ break;
+ case DefaultMasterRole::Right:
+ canonicalName = CommonStrings::masterPageNormalRight;
+ break;
+ case DefaultMasterRole::Middle:
+ canonicalName = CommonStrings::masterPageNormalMiddle;
+ break;
+ case DefaultMasterRole::Spread:
+ canonicalName = CommonStrings::masterPageNormalSpread;
+ break;
+ case DefaultMasterRole::None:
+ break;
+ }
+ if (!canonicalName.isEmpty() && !names.contains(canonicalName))
+ names.append(canonicalName);
+ return names;
+}
+
+QUuid defaultMasterId(const ScribusDoc* doc, DefaultMasterRole role)
+{
+ const bool spreadRole = role == DefaultMasterRole::Spread;
+ for (const QString& name : defaultMasterNames(role))
+ {
+ const QUuid id = doc->masterPageId(name);
+ if (id.isNull())
+ continue;
+ if (doc->isMasterSpread(id) == spreadRole)
+ return id;
+ }
+ return QUuid();
+}
+}
+
+
/**
This class forwards change events for pages and pageitems to
the region occupied by this page or pageitem.
@@ -2834,7 +2930,8 @@
if (oldPageName != newPageName && MasterNames.contains(newPageName))
return false;
- Q_ASSERT(oldPageName != CommonStrings::masterPageNormal && oldPageName != CommonStrings::trMasterPageNormal);
+ if (isDefaultMasterPage(oldPageName))
+ return false;
for (int index : indices)
MasterPages.at(index)->setPageName(newPageName);
@@ -2868,6 +2965,8 @@
{
assert(masterPageMode());
assert( Pages->count() > 1 && Pages->count() > pageNumber );
+ if (pageNumber < 0 || pageNumber >= Pages->count() || isDefaultMasterPage(Pages->at(pageNumber)->pageName()))
+ return;
setCurrentPage(Pages->at(0));
ScPage* page = Pages->takeAt(pageNumber);
delete page;
@@ -2978,6 +3077,38 @@
return masterPageHasSide(masterId, MasterPageSide::Left) && masterPageHasSide(masterId, MasterPageSide::Right);
}
+bool ScribusDoc::isDefaultMasterPageName(const QString& pageName) const
+{
+ return defaultMasterRoleForName(pageName) != DefaultMasterRole::None;
+}
+
+QStringList ScribusDoc::defaultMasterPageNames() const
+{
+ QStringList names;
+ for (DefaultMasterRole role : { DefaultMasterRole::Single, DefaultMasterRole::Left, DefaultMasterRole::Right, DefaultMasterRole::Middle, DefaultMasterRole::Spread })
+ names.append(defaultMasterNames(role));
+ names.removeDuplicates();
+ return names;
+}
+
+QString ScribusDoc::translatedDefaultMasterPageName(const QString& pageName) const
+{
+ const DefaultMasterRole role = defaultMasterRoleForName(pageName);
+ return role == DefaultMasterRole::None ? pageName : defaultMasterName(role);
+}
+
+bool ScribusDoc::isDefaultMasterPage(const QString& pageName) const
+{
+ const DefaultMasterRole role = defaultMasterRoleForName(pageName);
+ if (role == DefaultMasterRole::None)
+ return false;
+
+ const QUuid id = masterPageId(pageName);
+ if (id.isNull())
+ return false;
+ return isMasterSpread(id) == (role == DefaultMasterRole::Spread);
+}
+
int ScribusDoc::appliedMasterPageIndex(const ScPage* page) const
{
if (!page)
@@ -3110,6 +3241,156 @@
return leftPage >= 0 && rightPage >= 0;
}
+void ScribusDoc::ensureDefaultMasterPages()
+{
+ const int columns = pageSets().at(m_docPrefsData.docSetupPrefs.pagePositioning).Columns;
+ UndoBlocker undoBlocker;
+
+ auto moveConflictingReservedMaster = [this](DefaultMasterRole role)
+ {
+ for (const QString& reservedName : defaultMasterNames(role))
+ {
+ const QUuid existingId = masterPageId(reservedName);
+ if (existingId.isNull())
+ continue;
+ const bool expectedSpread = role == DefaultMasterRole::Spread;
+ if (isMasterSpread(existingId) == expectedSpread)
+ continue;
+
+ const QString replacementName = getUniqueName(reservedName, MasterNames.keys());
+ renameMasterPage(existingId, replacementName);
+ }
+ };
+
+ auto ensureOnePageDefault = [this, &moveConflictingReservedMaster](DefaultMasterRole role) -> ScPage*
+ {
+ QUuid id = defaultMasterId(this, role);
+ if (!id.isNull())
+ {
+ const int index = masterPageIndex(id, MasterPageSide::Single);
+ return index >= 0 ? MasterPages.at(index) : nullptr;
+ }
+
+ moveConflictingReservedMaster(role);
+ ScPage* page = addMasterPage(MasterPages.count(), defaultMasterName(role));
+ switch (role)
+ {
+ case DefaultMasterRole::Left:
+ page->LeftPg = 1;
+ page->Margins.setLeft(page->initialMargins.right());
+ page->Margins.setRight(page->initialMargins.left());
+ break;
+ case DefaultMasterRole::Right:
+ page->LeftPg = 0;
+ page->Margins.setRight(page->initialMargins.right());
+ page->Margins.setLeft(page->initialMargins.left());
+ break;
+ case DefaultMasterRole::Middle:
+ page->LeftPg = 2;
+ page->Margins.setLeft(page->initialMargins.left());
+ page->Margins.setRight(page->initialMargins.left());
+ break;
+ case DefaultMasterRole::Single:
+ case DefaultMasterRole::Spread:
+ case DefaultMasterRole::None:
+ break;
+ }
+ return page;
+ };
+
+ if (columns == 1)
+ {
+ ensureOnePageDefault(DefaultMasterRole::Single);
+ return;
+ }
+
+ ScPage* leftDefault = ensureOnePageDefault(DefaultMasterRole::Left);
+ ScPage* rightDefault = ensureOnePageDefault(DefaultMasterRole::Right);
+ if (columns == 3 || columns == 4)
+ {
+ ensureOnePageDefault(DefaultMasterRole::Middle);
+ return;
+ }
+ if (columns != 2 || !defaultMasterId(this, DefaultMasterRole::Spread).isNull())
+ return;
+
+ moveConflictingReservedMaster(DefaultMasterRole::Spread);
+ const auto spread = addMasterSpread(MasterPages.count(), defaultMasterName(DefaultMasterRole::Spread));
+ spread.first->LeftPg = 1;
+ spread.second->LeftPg = 0;
+ if (leftDefault)
+ {
+ spread.first->copySizingProperties(leftDefault, leftDefault->Margins);
+ leftDefault->guides.copy(&spread.first->guides);
+ }
+ if (rightDefault)
+ {
+ spread.second->copySizingProperties(rightDefault, rightDefault->Margins);
+ rightDefault->guides.copy(&spread.second->guides);
+ }
+
+ // Default spreads can be created while the document is not in master-page
+ // mode, so reformPages() cannot position the pair at that point. Give the
+ // newly created spread valid geometry immediately.
+ const double spreadX = m_docPrefsData.displayPrefs.scratch.left();
+ const double spreadY = m_docPrefsData.displayPrefs.scratch.top();
+ spread.first->setXOffset(spreadX);
+ spread.first->setYOffset(spreadY);
+ spread.second->setXOffset(spreadX + spread.first->width());
+ spread.second->setYOffset(spreadY);
+}
+
+QUuid ScribusDoc::defaultMasterPageIdForLocation(PageLocation pageLocation) const
+{
+ const int columns = pageSets().at(m_docPrefsData.docSetupPrefs.pagePositioning).Columns;
+ if (columns == 1)
+ return defaultMasterId(this, DefaultMasterRole::Single);
+ if (pageLocation == LeftPage)
+ return defaultMasterId(this, DefaultMasterRole::Left);
+ if (pageLocation == RightPage)
+ return defaultMasterId(this, DefaultMasterRole::Right);
+ if (columns == 3 || columns == 4)
+ return defaultMasterId(this, DefaultMasterRole::Middle);
+ return QUuid();
+}
+
+void ScribusDoc::reconcileDefaultMasterPages()
+{
+ if (masterPageMode())
+ return;
+
+ for (int pageNumber = 0; pageNumber < DocPages.count(); ++pageNumber)
+ {
+ ScPage* page = DocPages.at(pageNumber);
+ QUuid currentId = page->appliedMasterPageId();
+ QString currentName;
+ if (!currentId.isNull())
+ currentName = masterPageName(currentId);
+ if (currentName.isEmpty())
+ currentName = page->masterPageName();
+
+ const DefaultMasterRole currentRole = defaultMasterRoleForName(currentName);
+ if (currentRole == DefaultMasterRole::None || currentRole == DefaultMasterRole::Spread)
+ continue;
+ if (!isDefaultMasterPage(currentName))
+ continue;
+
+ const QUuid targetId = defaultMasterPageIdForLocation(locationOfPage(pageNumber));
+ if (targetId.isNull())
+ continue;
+ if (page->appliedMasterPageId() == targetId && page->appliedMasterPageSide() == MasterPageSide::Single)
+ continue;
+
+ applyMasterPageInternal(targetId, MasterPageSide::Single, pageNumber, false);
+ }
+}
+
+void ScribusDoc::reconcileMasterPages()
+{
+ reconcileDefaultMasterPages();
+ reconcileMasterPageSides();
+}
+
void ScribusDoc::preserveMasterPageMarginsForLayoutChange(int oldPagePositioning)
{
if (oldPagePositioning < 0 || oldPagePositioning >= pageSets().count())
@@ -3185,46 +3466,38 @@
void ScribusDoc::replaceMasterPage(const QString& oldMasterPage)
{
+ const QUuid oldMasterId = masterPageId(oldMasterPage);
for (int pageIndex = 0; pageIndex < DocPages.count(); ++pageIndex)
{
ScPage* docPage = DocPages.at(pageIndex);
- if (docPage->masterPageName() != oldMasterPage)
+ QUuid appliedId = docPage->appliedMasterPageId();
+ if (appliedId.isNull())
+ appliedId = masterPageId(docPage->masterPageName());
+ if ((!oldMasterId.isNull() && appliedId != oldMasterId) ||
+ (oldMasterId.isNull() && docPage->masterPageName() != oldMasterPage))
continue;
- QString replacementName;
- const PageLocation pageLoc = locationOfPage(pageIndex);
- if (pageLoc == LeftPage && MasterNames.contains(CommonStrings::trMasterPageNormalLeft)
- && CommonStrings::trMasterPageNormalLeft != oldMasterPage)
- replacementName = CommonStrings::trMasterPageNormalLeft;
- else if (pageLoc == RightPage && MasterNames.contains(CommonStrings::trMasterPageNormalRight)
- && CommonStrings::trMasterPageNormalRight != oldMasterPage)
- replacementName = CommonStrings::trMasterPageNormalRight;
- else if (pageLoc == MiddlePage && MasterNames.contains(CommonStrings::trMasterPageNormalMiddle)
- && CommonStrings::trMasterPageNormalMiddle != oldMasterPage)
- replacementName = CommonStrings::trMasterPageNormalMiddle;
- else if (MasterNames.contains(CommonStrings::trMasterPageNormal)
- && CommonStrings::trMasterPageNormal != oldMasterPage)
- replacementName = CommonStrings::trMasterPageNormal;
-
- if (replacementName.isEmpty())
+ QUuid replacementId = defaultMasterPageIdForLocation(locationOfPage(pageIndex));
+ if (replacementId.isNull() || replacementId == oldMasterId)
{
for (auto it = MasterNames.cbegin(); it != MasterNames.cend(); ++it)
{
- if (it.key() != oldMasterPage)
+ const QUuid candidateId = masterPageId(it.key());
+ if (!candidateId.isNull() && candidateId != oldMasterId)
{
- replacementName = it.key();
+ replacementId = candidateId;
break;
}
}
}
- const QUuid replacementId = masterPageId(replacementName);
if (!replacementId.isNull())
applyMasterPage(replacementId, pageIndex);
}
}
+
void ScribusDoc::deletePage(int pageNumber)
{
assert( Pages->count() > 1 && Pages->count() > pageNumber );
@@ -3247,7 +3520,7 @@
m_undoManager->action(this, ss);
}
Pages->swapItemsAt(a, b);
- reconcileMasterPageSides();
+ reconcileMasterPages();
reformPages();
changed();
}
@@ -3301,7 +3574,7 @@
ss->set("PAGE_MOVE_NEWPOS", position);
m_undoManager->action(this, ss);
}
- reconcileMasterPageSides();
+ reconcileMasterPages();
reformPages();
if (m_View && m_ScMW)
{
@@ -7989,7 +8262,7 @@
addPageToAnnotLinks(annotLinksInsert, whereToInsert, copyCount);
addPageToSection(existingPage, whereToInsert, copyCount);
- reconcileMasterPageSides();
+ reconcileMasterPages();
if (lastDest != nullptr)
setCurrentPage(lastDest);
else
@@ -15141,37 +15414,7 @@
void ScribusDoc::createDefaultMasterPages()
{
- int setcol = pageSets()[m_docPrefsData.docSetupPrefs.pagePositioning].Columns;
- if (setcol == 1)
- {
- addMasterPage(0, CommonStrings::trMasterPageNormal);
- }
- else if (setcol == 2)
- {
- ScPage *lp = addMasterPage(0, CommonStrings::trMasterPageNormalLeft);
- lp->LeftPg = 1;
- lp->Margins.setLeft(lp->initialMargins.right());
- lp->Margins.setRight(lp->initialMargins.left());
- lp = addMasterPage(1, CommonStrings::trMasterPageNormalRight);
- lp->LeftPg = 0;
- lp->Margins.setRight(lp->initialMargins.right());
- lp->Margins.setLeft(lp->initialMargins.left());
- }
- else if ((setcol == 3) || (setcol == 4))
- {
- ScPage *lp = addMasterPage(0, CommonStrings::trMasterPageNormalLeft);
- lp->LeftPg = 1;
- lp->Margins.setLeft(lp->initialMargins.right());
- lp->Margins.setRight(lp->initialMargins.left());
- lp = addMasterPage(1, CommonStrings::trMasterPageNormalRight);
- lp->LeftPg = 0;
- lp->Margins.setRight(lp->initialMargins.right());
- lp->Margins.setLeft(lp->initialMargins.left());
- lp = addMasterPage(2, CommonStrings::trMasterPageNormalMiddle);
- lp->LeftPg = 2;
- lp->Margins.setLeft(lp->initialMargins.left());
- lp->Margins.setRight(lp->initialMargins.left());
- }
+ ensureDefaultMasterPages();
}
@@ -17747,8 +17990,11 @@
m_docPrefsData = prefsData;
double topDisplacement = prefsData.displayPrefs.scratch.top() - oldPrefsData.displayPrefs.scratch.top();
double leftDisplacement = prefsData.displayPrefs.scratch.left() - oldPrefsData.displayPrefs.scratch.left();
+ preserveMasterPageMarginsForLayoutChange(oldPrefsData.docSetupPrefs.pagePositioning);
applyPrefsPageSizingAndMargins(resizePages, resizeMasterPages, resizePageMargins, resizeMasterPageMargins);
- reconcileMasterPageSides();
+ if (prefsData.docSetupPrefs.pagePositioning != oldPrefsData.docSetupPrefs.pagePositioning)
+ ensureDefaultMasterPages();
+ reconcileMasterPages();
int docItemsCount = MasterItems.count();
for (int i = 0; i < docItemsCount; ++i)
Index: scribus/scribusdoc.h
===================================================================
--- scribus/scribusdoc.h (revision 27864)
+++ scribus/scribusdoc.h (working copy)
@@ -280,7 +280,12 @@
QList<PageItem*> masterItemsForMasterPage(const ScPage* masterPage) const;
MasterPageSide matchingMasterPageSide(const QUuid& masterId, int pageNumber) const;
bool documentSpreadPages(int pageNumber, int& leftPage, int& rightPage) const;
+ bool isDefaultMasterPageName(const QString& pageName) const;
+ QStringList defaultMasterPageNames() const;
+ QString translatedDefaultMasterPageName(const QString& pageName) const;
+ bool isDefaultMasterPage(const QString& pageName) const;
void preserveMasterPageMarginsForLayoutChange(int oldPagePositioning);
+ void reconcileMasterPages();
void reconcileMasterPageSides();
bool isMasterItemOnCurrentMaster(const PageItem* item) const;
//! @brief Replace a master page by default one
@@ -288,7 +293,7 @@
//! @brief Rename a master page
bool renameMasterPage(const QString& oldPageName, const QString& newPageName);
bool renameMasterPage(const QUuid& masterId, const QString& newPageName);
- //! @brief Create the default master pages based on the layout selected by the user, ie, Normal, Normal Left, etc.
+ //! @brief Ensure the built-in master pages required by the current layout, including Normal Spread for facing pages.
void createDefaultMasterPages();
//! @brief Create the requested pages in a new document, run after createDefaultMasterPages()
void createNewDocPages(int pageCount);
@@ -1388,6 +1393,9 @@
protected:
bool applyMasterPageInternal(const QUuid& masterId, MasterPageSide side, int pageNumber, bool recordUndo);
+ void ensureDefaultMasterPages();
+ void reconcileDefaultMasterPages();
+ QUuid defaultMasterPageIdForLocation(PageLocation pageLocation) const;
void addSymbols();
void applyPrefsPageSizingAndMargins(bool resizePages, bool resizeMasterPages, bool resizePageMargins, bool resizeMasterPageMargins);
bool m_hasGUI {false};
Index: scribus/ui/pagepalette_masterpages.cpp
===================================================================
--- scribus/ui/pagepalette_masterpages.cpp (revision 27864)
+++ scribus/ui/pagepalette_masterpages.cpp (working copy)
@@ -158,9 +158,9 @@
// allow to delete multiple pages in one step
foreach (QListWidgetItem * delItem, masterPageListBox->selectedItems())
{
- m_currentPage = delItem->text();
+ m_currentPage = delItem->data(Qt::UserRole).toString();
- if (isReservedName(m_currentPage))
+ if (m_doc->isDefaultMasterPage(m_currentPage))
continue;
QString extraWarn;
@@ -425,7 +425,8 @@
QString lastName;
for (int selectionIndex = 0; selectionIndex < selectedNames.count(); ++selectionIndex)
{
- QString name = getUniqueName(selectedNames.at(selectionIndex), m_doc->MasterNames);
+ QString name = getNonReservedName(selectedNames.at(selectionIndex));
+ name = getUniqueName(name, m_doc->MasterNames);
const QList<int> sourceIndices = indexGroups.value(selectionIndex);
if (sourceIndices.isEmpty())
continue;
@@ -468,8 +469,7 @@
bool deleteEnabled = true;
deleteEnabled &= (m_doc->MasterNames.count() > 1);
- deleteEnabled &= (m_currentPage != CommonStrings::masterPageNormal);
- deleteEnabled &= (m_currentPage != CommonStrings::trMasterPageNormal);
+ deleteEnabled &= !m_doc->isDefaultMasterPage(m_currentPage);
deleteButton->setEnabled(deleteEnabled);
if (m_doc->appMode == modeEditClip)
@@ -508,8 +508,7 @@
bool deleteEnabled = true;
deleteEnabled &= (m_doc->MasterNames.count() > 1);
- deleteEnabled &= (m_currentPage != CommonStrings::masterPageNormal);
- deleteEnabled &= (m_currentPage != CommonStrings::trMasterPageNormal);
+ deleteEnabled &= !m_doc->isDefaultMasterPage(m_currentPage);
deleteButton->setEnabled(deleteEnabled);
if (m_doc->appMode == modeEditClip)
@@ -533,17 +532,14 @@
masterPageListBox->clear();
for (auto it = m_doc->MasterNames.cbegin(); it != m_doc->MasterNames.cend(); ++it)
{
- QString mpName = it.key();
-
- if (it.key() == CommonStrings::masterPageNormal)
- mpName = CommonStrings::trMasterPageNormal;
+ QString mpName = getTranslatedReservedName(it.key());
QListWidgetItem* mpItem = new QListWidgetItem(mpName);
const QUuid masterId = m_doc->masterPageId(it.key());
const bool spread = m_doc->isMasterSpread(masterId);
mpItem->setIcon(IconManager::instance().loadIcon(spread ? "page-type-facing" : "page-type-single"));
mpItem->setToolTip(spread ? tr("Facing master spread") : tr("One-page master"));
- if (!isReservedName(mpName))
+ if (!m_doc->isDefaultMasterPage(it.key()))
mpItem->setFlags(mpItem->flags() |= Qt::ItemIsEditable);
else
mpItem->setFlags(mpItem->flags() &= ~Qt::ItemIsEditable);
@@ -551,12 +547,8 @@
mpItem->setData(Qt::UserRole, it.key());
masterPageListBox->addItem(mpItem);
}
- deleteButton->setEnabled(m_doc->MasterNames.count() != 1);
- if (masterPageName == CommonStrings::masterPageNormal)
- {
- masterPageName = CommonStrings::trMasterPageNormal;
- deleteButton->setEnabled(false);
- }
+ deleteButton->setEnabled(m_doc->MasterNames.count() != 1 && !m_doc->isDefaultMasterPage(masterPageName));
+ masterPageName = getTranslatedReservedName(masterPageName);
QList<QListWidgetItem *> itL = masterPageListBox->findItems(masterPageName, Qt::MatchExactly);
if (itL.count() != 0)
itL.at(0)->setSelected(true);
@@ -628,40 +620,17 @@
// FIXME: move to a new masterpages.h
bool PagePalette_MasterPages::isReservedName(const QString& name) const
{
- bool retval = name == CommonStrings::masterPageNormal ||
- name == CommonStrings::trMasterPageNormal ||
- name == CommonStrings::masterPageNormalLeft ||
- name == CommonStrings::trMasterPageNormalLeft ||
- name == CommonStrings::masterPageNormalMiddle ||
- name == CommonStrings::trMasterPageNormalMiddle ||
- name == CommonStrings::masterPageNormalRight ||
- name == CommonStrings::trMasterPageNormalRight;
- return retval;
+ return m_doc->isDefaultMasterPageName(name);
}
// FIXME: move to a new masterpages.h
QString PagePalette_MasterPages::getNonReservedName(const QString& name) const
{
- const QStringList reservedNames = {
- CommonStrings::masterPageNormal,
- CommonStrings::trMasterPageNormal,
- CommonStrings::trMasterPageNormalLeft,
- CommonStrings::trMasterPageNormalMiddle,
- CommonStrings::trMasterPageNormalRight
- };
- return getUniqueName(name, reservedNames);
+ return getUniqueName(name, m_doc->defaultMasterPageNames());
}
// FIXME: move to a new masterpages.h
QString PagePalette_MasterPages::getTranslatedReservedName(const QString& name) const
{
- if (name == CommonStrings::masterPageNormal)
- return CommonStrings::trMasterPageNormal;
- if (name == CommonStrings::masterPageNormalLeft)
- return CommonStrings::trMasterPageNormalLeft;
- if (name == CommonStrings::masterPageNormalMiddle)
- return CommonStrings::trMasterPageNormalMiddle;
- if (name == CommonStrings::masterPageNormalRight)
- return CommonStrings::trMasterPageNormalRight;
- return name;
+ return m_doc->translatedDefaultMasterPageName(name);
}
Index: scribus/ui/pagepalette_pages.cpp
===================================================================
--- scribus/ui/pagepalette_pages.cpp (revision 27864)
+++ scribus/ui/pagepalette_pages.cpp (working copy)
@@ -86,7 +86,7 @@
void PagePalette_Pages::deleteMasterPage(const QString &tmp)
{
- if (tmp == CommonStrings::trMasterPageNormal)
+ if (currView->m_doc->isDefaultMasterPage(tmp))
return;
QString extraWarn;
for (int i = 0; i < currView->m_doc->DocPages.count(); ++i)
@@ -313,10 +313,12 @@
connect(pageLayout, SIGNAL(firstPageChanged(int)), this, SLOT(handleFirstPage(int)));
currView->m_doc->preserveMasterPageMarginsForLayoutChange(oldPagePositioning);
- currView->m_doc->reconcileMasterPageSides();
+ currView->m_doc->createDefaultMasterPages();
+ currView->m_doc->reconcileMasterPages();
currView->reformPages();
currView->DrawNew();
currView->GotoPage(currView->m_doc->currentPageNumber());
+ rebuildMasters();
rebuildPages();
}
@@ -325,7 +327,7 @@
if (!currView)
return;
currView->m_doc->setPageSetFirstPage(currView->m_doc->pagePositioning(), fp);
- currView->m_doc->reconcileMasterPageSides();
+ currView->m_doc->reconcileMasterPages();
currView->reformPages();
currView->DrawNew();
currView->GotoPage(currView->m_doc->currentPageNumber());
@@ -337,7 +339,7 @@
if (!currView)
return;
currView->m_doc->setBindingDirection(direction);
- currView->m_doc->reconcileMasterPageSides();
+ currView->m_doc->reconcileMasterPages();
currView->reformPages();
currView->DrawNew();
currView->GotoPage(currView->m_doc->currentPageNumber());
| ||||
| Patch | Yes | ||||
| Date Modified | Username | Field | Change |
|---|---|---|---|
| 2026-09-27 05:45 | buttar | New Issue | |
| 2026-09-27 05:45 | buttar | Tag Attached: #please_test | |
| 2026-09-27 05:45 | buttar | File Added: tsm1-master-model-persistence-v1.01.patch | |
| 2026-09-27 05:45 | buttar | File Added: tsm2-spread-editor-v1.16.patch | |
| 2026-09-27 05:45 | buttar | File Added: tsm3-application-reflow-v1.05.patch | |
| 2026-09-27 05:45 | buttar | File Added: tsm4-cross-spread-rendering-v1.01.patch | |
| 2026-09-27 05:45 | buttar | File Added: tsm5-output-projection-v1.06.patch | |
| 2026-09-27 05:45 | buttar | File Added: tsm6-default-master-lifecycle-normal-spread-v1.04.patch | |
| 2026-09-27 05:50 | buttar | Note Added: 0054498 | |
| 2026-09-27 05:50 | buttar | File Added: spread-master1-PROPOSED.png | |
| 2026-09-27 13:15 | buttar | Note Added: 0054499 | |
| 2026-09-27 13:15 | buttar | File Added: apply-to-spread-PROPOSED.png | |
| 2026-09-27 13:15 | buttar | File Added: spread-master2-PROPOSED.png |