File indexing completed on 2024-05-26 16:15:51
0001 /* This file is part of the KDE project 0002 * Copyright (C) 2008 Girish Ramakrishnan <girish@forwardbias.in> 0003 * Copyright (C) 2010 Thomas Zander <zander@kde.org> 0004 * 0005 * This library is free software; you can redistribute it and/or 0006 * modify it under the terms of the GNU Library General Public 0007 * License as published by the Free Software Foundation; either 0008 * version 2 of the License, or (at your option) any later version. 0009 * 0010 * This library is distributed in the hope that it will be useful, 0011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0013 * Library General Public License for more details. 0014 * 0015 * You should have received a copy of the GNU Library General Public License 0016 * along with this library; see the file COPYING.LIB. If not, write to 0017 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 0018 * Boston, MA 02110-1301, USA. 0019 */ 0020 0021 #include "KoList.h" 0022 #include "KoList_p.h" 0023 0024 #include "KoTextDocument.h" 0025 #include "styles/KoListLevelProperties.h" 0026 #include "styles/KoParagraphStyle.h" 0027 #include "styles/KoStyleManager.h" 0028 0029 #include "TextDebug.h" 0030 0031 #include <QTextCursor> 0032 0033 KoList::KoList(const QTextDocument *document, KoListStyle *style, KoList::Type type) 0034 : QObject(const_cast<QTextDocument *>(document)), d(new KoListPrivate(this, document)) 0035 { 0036 Q_ASSERT(document); 0037 d->type = type; 0038 setStyle(style); 0039 KoTextDocument(document).addList(this); 0040 } 0041 0042 KoList::~KoList() 0043 { 0044 KoTextDocument(d->document).removeList(this); 0045 delete d; 0046 } 0047 0048 QVector<QPointer<QTextList> > KoList::textLists() const 0049 { 0050 return d->textLists; 0051 } 0052 0053 QVector<KoListStyle::ListIdType> KoList::textListIds() const 0054 { 0055 return d->textListIds; 0056 } 0057 0058 KoList *KoList::applyStyle(const QTextBlock &block, KoListStyle *style, int level) 0059 { 0060 Q_ASSERT(style); 0061 KoTextDocument document(block.document()); 0062 KoList *list = document.list(block); 0063 if (list && *list->style() == *style) { 0064 list->add(block, level); 0065 return list; 0066 } 0067 0068 //the block was already another list but with a different style - remove block from list 0069 if (list) 0070 list->remove(block); 0071 0072 // Ok, so we are now ready to add the block to another list, but which other list? 0073 // For headers we always want to continue from any previous header 0074 // For normal lists we either want to continue an adjacent list or create a new one 0075 if (block.blockFormat().hasProperty(KoParagraphStyle::OutlineLevel)) { 0076 for (QTextBlock b = block.previous();b.isValid(); b = b.previous()) { 0077 list = document.list(b); 0078 if (list && *list->style() == *style) { 0079 break; 0080 } 0081 } 0082 if (!list || *list->style() != *style) { 0083 list = new KoList(block.document(), style); 0084 } 0085 } else { 0086 list = document.list(block.previous()); 0087 if (!list || *list->style() != *style) { 0088 list = document.list(block.next()); 0089 if (!list || *list->style() != *style) { 0090 list = new KoList(block.document(), style); 0091 } 0092 } 0093 } 0094 list->add(block, level); 0095 return list; 0096 } 0097 0098 void KoList::add(const QTextBlock &block, int level) 0099 { 0100 if (!block.isValid()) 0101 return; 0102 0103 Q_ASSERT(level >= 0 && level <= 10); 0104 if (level == 0) { // fetch the first proper level we have 0105 level = 1; // if nothing works... 0106 for (int i = 1; i <= 10; i++) { 0107 if (d->style->hasLevelProperties(i)) { 0108 level = i; 0109 break; 0110 } 0111 } 0112 } 0113 remove(block); 0114 0115 QTextList *textList = d->textLists.value(level-1).data(); 0116 if (!textList) { 0117 QTextCursor cursor(block); 0118 QTextListFormat format = d->style->listFormat(level); 0119 textList = cursor.createList(format); 0120 format.setProperty(KoListStyle::ListId, (KoListStyle::ListIdType)(textList)); 0121 textList->setFormat(format); 0122 d->textLists[level-1] = textList; 0123 d->textListIds[level-1] = (KoListStyle::ListIdType)textList; 0124 } else { 0125 textList->add(block); 0126 } 0127 0128 QTextCursor cursor(block); 0129 QTextBlockFormat blockFormat = cursor.blockFormat(); 0130 if (d->style->styleId()) { 0131 blockFormat.setProperty(KoParagraphStyle::ListStyleId, d->style->styleId()); 0132 } else { 0133 blockFormat.clearProperty(KoParagraphStyle::ListStyleId); 0134 } 0135 if (d->type == KoList::TextList) { 0136 blockFormat.clearProperty(KoParagraphStyle::ListLevel); 0137 } else { 0138 blockFormat.setProperty(KoParagraphStyle::ListLevel, level); 0139 } 0140 cursor.setBlockFormat(blockFormat); 0141 0142 d->invalidate(block); 0143 } 0144 0145 void KoList::remove(const QTextBlock &block) 0146 { 0147 //QTextLists are created with a blockIndent of 1. When a block is removed from a QTextList, it's blockIndent is set to (block.indent + list.indent). 0148 //Since we do not use Qt's indentation for lists, we need to clear the block's blockIndent, otherwise the block's style will appear as modified. 0149 bool clearIndent = !block.blockFormat().hasProperty(4160); 0150 0151 if (QTextList *textList = block.textList()) { 0152 // invalidate the list before we remove the item 0153 // (since the list might disappear if the block is the only item) 0154 KoListPrivate::invalidateList(block); 0155 textList->remove(block); 0156 } 0157 KoListPrivate::invalidate(block); 0158 0159 if (clearIndent) { 0160 QTextBlockFormat format = block.blockFormat(); 0161 format.clearProperty(4160); 0162 QTextCursor cursor(block); 0163 cursor.setBlockFormat(format); 0164 } 0165 } 0166 0167 void KoList::setStyle(KoListStyle *style) 0168 { 0169 if (style == 0) { 0170 KoStyleManager *styleManager = KoTextDocument(d->document).styleManager(); 0171 Q_ASSERT(styleManager); 0172 style = styleManager->defaultListStyle(); 0173 } 0174 0175 if (style != d->style) { 0176 if (d->style) 0177 disconnect(d->style, 0, this, 0); 0178 d->style = style->clone(this); 0179 connect(d->style, SIGNAL(styleChanged(int)), this, SLOT(styleChanged(int))); 0180 } 0181 0182 for (int i = 0; i < d->textLists.count(); i++) { 0183 QTextList *textList = d->textLists.value(i).data(); 0184 if (!textList) 0185 continue; 0186 KoListLevelProperties properties = d->style->levelProperties(i+1); 0187 if (properties.listId()) 0188 d->textListIds[i] = properties.listId(); 0189 QTextListFormat format; 0190 properties.applyStyle(format); 0191 textList->setFormat(format); 0192 d->invalidate(textList->item(0)); 0193 } 0194 0195 //if this list is a heading list then update the style manager with the list properties 0196 if (KoTextDocument(d->document).headingList() == this) { 0197 if (KoStyleManager *styleManager = KoTextDocument(d->document).styleManager()) { 0198 if (styleManager->outlineStyle()) { 0199 styleManager->outlineStyle()->copyProperties(style); 0200 } 0201 } 0202 } 0203 } 0204 0205 KoListStyle *KoList::style() const 0206 { 0207 return d->style; 0208 } 0209 0210 void KoList::updateStoredList(const QTextBlock &block) 0211 { 0212 if (block.textList()) { 0213 int level = block.textList()->format().property(KoListStyle::Level).toInt(); 0214 QTextList *textList = block.textList(); 0215 textList->format().setProperty(KoListStyle::ListId, (KoListStyle::ListIdType)(textList)); 0216 d->textLists[level-1] = textList; 0217 d->textListIds[level-1] = (KoListStyle::ListIdType)textList; 0218 } 0219 } 0220 0221 bool KoList::contains(QTextList *list) const 0222 { 0223 return list && d->textLists.contains(list); 0224 } 0225 0226 int KoList::level(const QTextBlock &block) 0227 { 0228 if (!block.textList()) 0229 return 0; 0230 int l = block.blockFormat().intProperty(KoParagraphStyle::ListLevel); 0231 if (!l) { // not a numbered-paragraph 0232 QTextListFormat format = block.textList()->format(); 0233 l = format.intProperty(KoListStyle::Level); 0234 } 0235 return l; 0236 } 0237 0238 KoList *KoList::listContinuedFrom() const 0239 { 0240 return d->listToBeContinuedFrom; 0241 } 0242 0243 void KoList::setListContinuedFrom(KoList *list) 0244 { 0245 d->listToBeContinuedFrom = list; 0246 } 0247 0248 //have to include this because of Q_PRIVATE_SLOT 0249 #include "moc_KoList.cpp"