File indexing completed on 2024-05-19 16:09:58

0001 /* This file is part of the Calligra project
0002  * Copyright (C) 2005-2010 Thomas Zander <zander@kde.org>
0003  * Copyright (C) 2008 Pierre Ducroquet <pinaraf@pinaraf.info>
0004  * Copyright (C) 2008,2011 Sebastian Sauer <mail@dipe.org>
0005  *
0006  * This library is free software; you can redistribute it and/or
0007  * modify it under the terms of the GNU Library General Public
0008  * License as published by the Free Software Foundation; either
0009  * version 2 of the License, or (at your option) any later version.
0010  *
0011  * This library is distributed in the hope that it will be useful,
0012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0014  * Library General Public License for more details.
0015  *
0016  * You should have received a copy of the GNU Library General Public License
0017  * along with this library; see the file COPYING.LIB.  If not, write to
0018  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0019  * Boston, MA 02110-1301, USA.
0020  */
0021 #include "KWPageManager.h"
0022 #include "KWPageManager_p.h"
0023 #include "KWPageStyle_p.h"
0024 #include "KWPage.h"
0025 #include "KWDocument.h"
0026 
0027 #include <KoShape.h>
0028 
0029 #include <WordsDebug.h>
0030 
0031 #define DEBUG_PAGES
0032 
0033 KWPageManagerPrivate::KWPageManagerPrivate()
0034         : lastId(0),
0035         defaultPageStyle(QLatin1String("Standard")) // don't translate, used as identifier!
0036 {
0037 }
0038 
0039 qreal KWPageManagerPrivate::pageOffset(int pageNum/*, bool bottom*/) const
0040 {
0041 #if 0
0042     Q_ASSERT(pageNum >= 0);
0043     qreal offset = 0.0;
0044     const qreal totalPadding = padding.top + padding.bottom;
0045 
0046     QMap<int, int>::const_iterator iter = pageNumbers.constBegin();
0047     for (;iter != pageNumbers.constEnd(); ++iter) {
0048         const KWPageManagerPrivate::Page &page = pages[iter.value()];
0049         if (page.pageSide == KWPage::PageSpread && iter.key() % 2 == 1)
0050             continue;
0051         if (iter.key() == pageNum) {
0052             if (bottom)
0053                 offset += page.style.pageLayout().height;
0054             break;
0055         }
0056         offset += page.style.priv()->pageLayout.height + totalPadding;
0057     }
0058     return offset;
0059 #else
0060     //Q_ASSERT(pageOffsets.contains(pageNum));
0061     qreal offset = pageOffsets.value(pageNum);
0062     //debugWords << "pageNum=" << pageNum << "offset=" << offset;
0063     return offset;
0064 #endif
0065 }
0066 
0067 void KWPageManagerPrivate::setPageOffset(int pageNum, qreal offset)
0068 {
0069     pageOffsets[pageNum] = offset;
0070 }
0071 
0072 void KWPageManagerPrivate::setVisiblePageNumber(int pageId, int newPageNumber)
0073 {
0074 #if 0
0075     if (pageNumbers.isEmpty() || ! pages.contains(pageId))
0076         return;
0077     const int oldPageNumber = pages[pageId].pageNumber;
0078     int diff = newPageNumber - oldPageNumber;
0079     int from = oldPageNumber;
0080     int to = newPageNumber;
0081     if (from > to)
0082         qSwap(from, to);
0083 
0084     QMap<int, int> oldPageNumbers = pageNumbers; // backup
0085     QHash<int, Page> oldPages = pages; // backup
0086 
0087     pageNumbers.clear();
0088     pages.clear();
0089 
0090     foreach (int id, oldPages.keys()) {
0091         Page page = oldPages[id];
0092         if (diff < 0 && page.pageNumber >= from && page.pageNumber < to) {
0093             warnWords << "you requested to change the page number to a number that already exist, all will end soon";
0094             return;
0095         }
0096 #ifdef DEBUG_PAGES
0097         const int oldPageNumber = page.pageNumber; // debug only
0098 #endif
0099         if (page.pageNumber >= from)
0100             page.pageNumber += diff;
0101 #ifdef DEBUG_PAGES
0102         debugWords << "adjusting page number from" << oldPageNumber << "to" << page.pageNumber << "side" << page.pageSide;
0103 #endif
0104         if (page.pageSide == KWPage::PageSpread) {
0105             if (page.pageNumber % 2 == 1) { // pagespreads can only be on even pageNumbers
0106                 page.pageNumber++;
0107                 diff++;
0108             }
0109             pageNumbers.insert(page.pageNumber + 1, id);
0110         }
0111         else {
0112             page.pageSide = page.pageNumber % 2 == 0 ? KWPage::Left : KWPage::Right;
0113         }
0114         pageNumbers.insert(page.pageNumber, id);
0115         pages.insert(id, page);
0116     }
0117 
0118     Q_ASSERT(pages.count() == oldPages.count()); // don't loose anything :)
0119 #else
0120     if (newPageNumber >= 0)
0121         visiblePageNumbers[pageId] = newPageNumber;
0122     else
0123         visiblePageNumbers.remove(pageId);
0124 #endif
0125 }
0126 
0127 void KWPageManagerPrivate::insertPage(const Page &newPage)
0128 {
0129 #ifdef DEBUG_PAGES
0130     debugWords << "pageNumber=" << newPage.pageNumber;
0131 #endif
0132 
0133     // increase the pagenumbers of pages following the pageNumber
0134     if (!pageNumbers.isEmpty()) {
0135         const QMap<int, int> numbers = pageNumbers;
0136         QMap<int, int>::ConstIterator iter = numbers.end();
0137         do {
0138             --iter;
0139 
0140             if (iter.key() < newPage.pageNumber)
0141                 break;
0142             KWPageManagerPrivate::Page page = pages[iter.value()];
0143             pageNumbers.remove(iter.key());
0144             page.pageNumber += 1;
0145             pages.insert(iter.value(), page);
0146             pageNumbers.insert(iter.key() + 1, iter.value());
0147         } while (iter != numbers.begin());
0148     }
0149 
0150     pages.insert(++lastId, newPage);
0151     Q_ASSERT(! pageNumbers.contains(newPage.pageNumber));
0152     pageNumbers.insert(newPage.pageNumber, lastId);
0153 }
0154 
0155 ///////////
0156 
0157 KWPageManager::KWPageManager()
0158     : d (new KWPageManagerPrivate())
0159 {
0160     addPageStyle(d->defaultPageStyle);
0161 }
0162 
0163 KWPageManager::~KWPageManager()
0164 {
0165     delete d;
0166 }
0167 
0168 int KWPageManager::pageNumber(const QPointF &point) const
0169 {
0170     qreal startOfpage = 0.0;
0171     int answer = -1;
0172     QMap<int, int>::const_iterator iter = d->pageNumbers.constBegin();
0173     for (;iter != d->pageNumbers.constEnd(); ++iter) {
0174         const KWPageManagerPrivate::Page page = d->pages[iter.value()];
0175         startOfpage += page.style.pageLayout().height + d->padding.top + d->padding.bottom;
0176         answer = iter.key();
0177         if (startOfpage >= point.y())
0178             break;
0179     }
0180     return answer;
0181 }
0182 
0183 int KWPageManager::pageNumber(const KoShape *shape) const
0184 {
0185     return pageNumber(shape->absolutePosition());
0186 }
0187 
0188 int KWPageManager::pageNumber(const qreal y) const
0189 {
0190     return pageNumber(QPointF(0, y));
0191 }
0192 
0193 int KWPageManager::pageCount() const
0194 {
0195     int count = 0;
0196     QHash<int,KWPageManagerPrivate::Page>::const_iterator iter = d->pages.constBegin();
0197     while (iter != d->pages.constEnd()) {
0198         ++count;
0199         ++iter;
0200     }
0201     return count;
0202 }
0203 
0204 KWPage KWPageManager::page(int pageNum) const
0205 {
0206     if (d->pageNumbers.contains(pageNum))
0207         return KWPage(d, d->pageNumbers.value(pageNum));
0208 
0209 #ifdef DEBUG_PAGES
0210     warnWords << "KWPageManager::page(" << pageNum << ") failed; Requested page does not exist";
0211 #endif
0212     return KWPage();
0213 }
0214 
0215 KWPage KWPageManager::page(const KoShape *shape) const
0216 {
0217     return page(pageNumber(shape));
0218 }
0219 
0220 KWPage KWPageManager::page(const QPointF &point) const
0221 {
0222     return page(pageNumber(point));
0223 }
0224 
0225 KWPage KWPageManager::page(qreal y) const
0226 {
0227     return page(pageNumber(y));
0228 }
0229 
0230 KWPage KWPageManager::insertPage(int pageNumber, const KWPageStyle &pageStyle)
0231 {
0232     if (pageNumber <= 0 || d->pages.isEmpty() || pageNumber > last().pageNumber())
0233         return appendPage(pageStyle);
0234 
0235 #ifdef DEBUG_PAGES
0236     debugWords << "pageNumber=" << pageNumber << "pageStyle=" << (pageStyle.isValid() ? pageStyle.name() : QString());
0237 #endif
0238 
0239     KWPageManagerPrivate::Page newPage;
0240     newPage.style = pageStyle;
0241 
0242     KWPage prevPage = page(pageNumber - 1);
0243     if (prevPage.isValid()) {
0244         if (! newPage.style.isValid())
0245             newPage.style = prevPage.pageStyle();
0246     }
0247 
0248     if (! newPage.style.isValid())
0249         newPage.style = defaultPageStyle();
0250     newPage.pageNumber = pageNumber;
0251     if (newPage.pageNumber % 2 == 0) {
0252         newPage.pageSide = KWPage::Left;
0253     } else {
0254         newPage.pageSide = KWPage::Right;
0255     }
0256 
0257     d->insertPage(newPage);
0258 
0259     return KWPage(d, d->lastId);
0260 }
0261 
0262 KWPage KWPageManager::appendPage(const KWPageStyle &pageStyle)
0263 {
0264     KWPageManagerPrivate::Page page;
0265 
0266     if (! d->pages.isEmpty()) {
0267         QMap<int, int>::ConstIterator end = d->pageNumbers.constEnd();
0268         --end; // last one is one before the imaginary 'end'
0269         KWPageManagerPrivate::Page lastPage = d->pages[end.value()];
0270         page = lastPage;
0271         ++page.pageNumber;
0272     } else {
0273         page.pageNumber = 1;
0274     }
0275 
0276     if (pageStyle.isValid()) {
0277         page.style = pageStyle;
0278     } else {
0279         if (page.style.isValid()) {
0280             QString nextPageMasterStyleName = page.style.nextStyleName();
0281             KWPageStyle nextPageMasterStyle = this->pageStyle(nextPageMasterStyleName);
0282             if (nextPageMasterStyle.isValid()) {
0283                 page.style = nextPageMasterStyle;
0284             }
0285         }
0286     }
0287     if (!page.style.isValid()) {
0288         page.style = defaultPageStyle();
0289     }
0290 
0291     if (page.pageNumber % 2 == 0) {
0292         page.pageSide = KWPage::Left;
0293     } else {
0294         page.pageSide = KWPage::Right;
0295     }
0296 
0297     d->pages.insert(++d->lastId, page);
0298     d->pageNumbers.insert(page.pageNumber, d->lastId);
0299 
0300 #ifdef DEBUG_PAGES
0301     debugWords << "pageNumber=" << page.pageNumber << "pageCount=" << pageCount() << "pageStyle=" << (pageStyle.isValid() ? pageStyle.name() : QString());
0302 #endif
0303 
0304     return KWPage(d, d->lastId);
0305 }
0306 
0307 qreal KWPageManager::topOfPage(int pageNum) const
0308 {
0309     return d->pageOffset(pageNum);
0310 }
0311 
0312 qreal KWPageManager::bottomOfPage(int pageNum) const
0313 {
0314     KWPage p = page(pageNum);
0315     Q_ASSERT(p.isValid());
0316     return d->pageOffset(pageNum) + p.height();
0317 }
0318 
0319 void KWPageManager::removePage(int pageNumber)
0320 {
0321     removePage(page(pageNumber));
0322 }
0323 
0324 void KWPageManager::removePage(const KWPage &page)
0325 {
0326     Q_ASSERT(page.isValid());
0327     debugWords << page.pageNumber();
0328 
0329     const int removedPageNumber = page.pageNumber();
0330     d->pages.remove(d->pageNumbers[removedPageNumber]);
0331     d->visiblePageNumbers.remove(removedPageNumber);
0332 
0333     // decrease the pagenumbers of pages following the pageNumber
0334     const QMap<int, int> pageNumbers = d->pageNumbers;
0335     QMap<int, int>::ConstIterator iter = pageNumbers.begin();
0336     while (iter != pageNumbers.end()) {
0337         if (iter.key() < removedPageNumber) {
0338             //  don't touch those
0339         } else if (iter.key() > removedPageNumber) {
0340             KWPageManagerPrivate::Page page = d->pages[iter.value()];
0341             d->pageNumbers.remove(iter.key());
0342             page.pageNumber--;
0343             d->pages.insert(iter.value(), page);
0344             d->pageNumbers.insert(page.pageNumber, iter.value());
0345         } else {
0346             d->pageNumbers.remove(iter.key());
0347         }
0348         ++iter;
0349     }
0350 
0351 #ifdef DEBUG_PAGES
0352     debugWords << "pageNumber=" << removedPageNumber << "pageCount=" << pageCount();
0353 #endif
0354 }
0355 
0356 QVector<KWPage> KWPageManager::pages(const QString &pageStyle) const
0357 {
0358     QVector<KWPage> answer;
0359     const bool checkForStyle = !pageStyle.isEmpty();
0360     QHash<int, KWPageManagerPrivate::Page>::ConstIterator it = d->pages.constBegin();
0361     QHash<int, KWPageManagerPrivate::Page>::ConstIterator end = d->pages.constEnd();
0362     for(; it != end; ++it) {
0363         if (checkForStyle && it.value().style.name() != pageStyle)
0364             continue;
0365         answer << KWPage(d, it.key());
0366     }
0367     std::sort(answer.begin(), answer.end());
0368     return answer;
0369 }
0370 
0371 QHash<QString, KWPageStyle> KWPageManager::pageStyles() const
0372 {
0373     return d->pageStyles;
0374 }
0375 
0376 KWPageStyle KWPageManager::pageStyle(const QString &name) const
0377 {
0378     if (d->pageStyles.contains(name))
0379         return d->pageStyles[name];
0380     if (d->pageStyleNames.contains(name))
0381         return d->pageStyles[d->pageStyleNames[name]];
0382     return KWPageStyle();
0383 }
0384 
0385 void KWPageManager::addPageStyle(const KWPageStyle &pageStyle)
0386 {
0387     Q_ASSERT(!pageStyle.name().isEmpty());
0388     Q_ASSERT(pageStyle.isValid());
0389     d->pageStyles.insert(pageStyle.name(), pageStyle);
0390     if (!pageStyle.displayName().isEmpty())
0391         d->pageStyleNames.insert(pageStyle.displayName(), pageStyle.name());
0392 }
0393 
0394 void KWPageManager::removePageStyle(const KWPageStyle &pageStyle)
0395 {
0396     KWPageStyle style = d->pageStyles.value(pageStyle.name());
0397     Q_ASSERT(style == pageStyle);
0398     d->pageStyles.remove(pageStyle.name());
0399     Q_ASSERT(!d->pageStyleNames.contains(pageStyle.displayName()) || d->pageStyleNames[pageStyle.displayName()] == pageStyle.name());
0400     d->pageStyleNames.remove(pageStyle.displayName());
0401 }
0402 
0403 KWPageStyle KWPageManager::defaultPageStyle() const
0404 {
0405     return d->defaultPageStyle;
0406 }
0407 
0408 void KWPageManager::clearPageStyles()
0409 {
0410     d->pageStyles.clear();
0411     d->pageStyleNames.clear();
0412     d->defaultPageStyle = KWPageStyle(QLatin1String("Standard")); // don't translate, used as identifier!
0413     addPageStyle(d->defaultPageStyle);
0414 }
0415 
0416 const KWPage KWPageManager::begin() const
0417 {
0418     if (d->pages.isEmpty() || d->pageNumbers.empty())
0419         return KWPage();
0420     return KWPage(d, d->pageNumbers.constBegin().value());
0421 }
0422 
0423 const KWPage KWPageManager::last() const
0424 {
0425     if (d->pages.isEmpty() || d->pageNumbers.empty())
0426         return KWPage();
0427     QMap<int, int>::ConstIterator end = d->pageNumbers.constEnd();
0428     --end; // last one is one before the imaginary 'end'
0429     return KWPage(d, end.value());
0430 }
0431 
0432 KWPage KWPageManager::begin()
0433 {
0434     if (d->pages.isEmpty() || d->pageNumbers.empty())
0435         return KWPage();
0436     return KWPage(d, d->pageNumbers.begin().value());
0437 }
0438 
0439 KWPage KWPageManager::last()
0440 {
0441     if (d->pages.isEmpty() || d->pageNumbers.empty())
0442         return KWPage();
0443     QMap<int, int>::ConstIterator end = d->pageNumbers.constEnd();
0444     --end; // last one is one before the imaginary 'end'
0445     return KWPage(d, end.value());
0446 }
0447 
0448 KoInsets KWPageManager::padding() const
0449 {
0450     return d->padding;
0451 }
0452 
0453 void KWPageManager::setPadding(const KoInsets &padding)
0454 {
0455     d->padding = padding;
0456 }