1 /* This file is part of the KDE project
2 * Copyright (C) 2006-2010 Thomas Zander <zander@kde.org>
3 * Copyright (C) 2007-2010 Sebastian Sauer <mail@dipe.org>
4 * Copyright (C) 2008 Girish Ramakrishnan <girish@forwardbias.in>
5 * Copyright (C) 2011-2012 Gopalakrishna Bhat A <gopalakbhat@gmail.com>
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
16 *
17 * You should have received a copy of the GNU Library General Public License
18 * along with this library; see the file COPYING.LIB. If not, write to
19 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 * Boston, MA 02110-1301, USA.
21 */
22
23 #include "KoListStyle.h"
24
25 #include "KoListLevelProperties.h"
26 #include "KoList.h"
27
28 #include <KoXmlNS.h>
29 #include <KoXmlWriter.h>
30 #include <KoGenStyle.h>
31 #include "TextDebug.h"
32 #include <QBuffer>
33
34 class Q_DECL_HIDDEN KoListStyle::Private
35 {
36 public:
Private()37 Private() : styleId(0) { }
38
39 QString name;
40 int styleId;
41 QMap<int, KoListLevelProperties> levels;
42 };
43
KoListStyle(QObject * parent)44 KoListStyle::KoListStyle(QObject *parent)
45 : QObject(parent), d(new Private())
46 {
47 }
48
~KoListStyle()49 KoListStyle::~KoListStyle()
50 {
51 delete d;
52 }
53
operator ==(const KoListStyle & other) const54 bool KoListStyle::operator==(const KoListStyle &other) const
55 {
56 Q_FOREACH (int level, d->levels.keys()) {
57 if (! other.hasLevelProperties(level))
58 return false;
59 if (!(other.levelProperties(level) == d->levels[level]))
60 return false;
61 }
62 Q_FOREACH (int level, other.d->levels.keys()) {
63 if (! hasLevelProperties(level))
64 return false;
65 }
66 return true;
67 }
68
operator !=(const KoListStyle & other) const69 bool KoListStyle::operator!=(const KoListStyle &other) const
70 {
71 return !KoListStyle::operator==(other);
72 }
73
copyProperties(KoListStyle * other)74 void KoListStyle::copyProperties(KoListStyle *other)
75 {
76 d->styleId = other->d->styleId;
77 d->levels = other->d->levels;
78 setName(other->name());
79 }
80
clone(QObject * parent)81 KoListStyle *KoListStyle::clone(QObject *parent)
82 {
83 KoListStyle *newStyle = new KoListStyle(parent);
84 newStyle->copyProperties(this);
85 return newStyle;
86 }
87
name() const88 QString KoListStyle::name() const
89 {
90 return d->name;
91 }
92
setName(const QString & name)93 void KoListStyle::setName(const QString &name)
94 {
95 if (d->name == name)
96 return;
97 d->name = name;
98 emit nameChanged(d->name);
99 }
100
styleId() const101 int KoListStyle::styleId() const
102 {
103 return d->styleId;
104 }
105
setStyleId(int id)106 void KoListStyle::setStyleId(int id)
107 {
108 d->styleId = id;
109 Q_FOREACH (int level, d->levels.keys()) {
110 d->levels[level].setStyleId(id);
111 }
112 }
113
levelProperties(int level) const114 KoListLevelProperties KoListStyle::levelProperties(int level) const
115 {
116 if (d->levels.contains(level))
117 return d->levels.value(level);
118
119 level = qMax(1, level);
120 if (d->levels.count()) {
121 KoListLevelProperties llp = d->levels.begin().value();
122 llp.setLevel(level);
123 return llp;
124 }
125 KoListLevelProperties llp;
126 llp.setLevel(level);
127 if (d->styleId)
128 llp.setStyleId(d->styleId);
129 return llp;
130 }
131
listFormat(int level) const132 QTextListFormat KoListStyle::listFormat(int level) const
133 {
134 KoListLevelProperties llp = levelProperties(level);
135 QTextListFormat format;
136 llp.applyStyle(format);
137 return format;
138 }
139
setLevelProperties(const KoListLevelProperties & properties)140 void KoListStyle::setLevelProperties(const KoListLevelProperties &properties)
141 {
142 int level = qMax(1, properties.level());
143 refreshLevelProperties(properties);
144 emit styleChanged(level);
145 }
146
refreshLevelProperties(const KoListLevelProperties & properties)147 void KoListStyle::refreshLevelProperties(const KoListLevelProperties &properties)
148 {
149 int level = qMax(1, properties.level());
150 KoListLevelProperties llp = properties;
151 if (isOulineStyle()) {
152 llp.setOutlineList(true);
153 }
154 llp.setLevel(level);
155 d->levels.insert(level, llp);
156 }
157
hasLevelProperties(int level) const158 bool KoListStyle::hasLevelProperties(int level) const
159 {
160 return d->levels.contains(level);
161 }
162
removeLevelProperties(int level)163 void KoListStyle::removeLevelProperties(int level)
164 {
165 d->levels.remove(level);
166 }
167
applyStyle(const QTextBlock & block,int level)168 void KoListStyle::applyStyle(const QTextBlock &block, int level)
169 {
170 KoList::applyStyle(block, this, level);
171 }
172
loadOdf(KoShapeLoadingContext & scontext,const KoXmlElement & style)173 void KoListStyle::loadOdf(KoShapeLoadingContext& scontext, const KoXmlElement& style)
174 {
175 d->name = style.attributeNS(KoXmlNS::style, "display-name", QString());
176 // if no style:display-name is given us the style:name
177 if (d->name.isEmpty()) {
178 d->name = style.attributeNS(KoXmlNS::style, "name", QString());
179 }
180 d->name = style.attributeNS(KoXmlNS::style, "name", QString());
181
182 KoXmlElement styleElem;
183 forEachElement(styleElem, style) {
184 KoListLevelProperties properties;
185 properties.loadOdf(scontext, styleElem);
186 if (d->styleId)
187 properties.setStyleId(d->styleId);
188 setLevelProperties(properties);
189 }
190
191 if (d->levels.isEmpty()) {
192 KoListLevelProperties llp;
193 llp.setLevel(1);
194 llp.setStartValue(1);
195 llp.setStyle(KoListStyle::DecimalItem);
196 llp.setListItemSuffix(".");
197 setLevelProperties(llp);
198 }
199 }
200
saveOdf(KoGenStyle & style,KoShapeSavingContext & context) const201 void KoListStyle::saveOdf(KoGenStyle &style, KoShapeSavingContext &context) const
202 {
203 // style:display-name can be used in list styles but not in outline styles
204 if (!d->name.isEmpty() && !style.isDefaultStyle() && !isOulineStyle()) {
205 style.addAttribute("style:display-name", d->name);
206 }
207 QBuffer buffer;
208 buffer.open(QIODevice::WriteOnly);
209 KoXmlWriter elementWriter(&buffer); // TODO pass indentation level
210 QMapIterator<int, KoListLevelProperties> it(d->levels);
211 while (it.hasNext()) {
212 it.next();
213 it.value().saveOdf(&elementWriter, context);
214 }
215 QString elementContents = QString::fromUtf8(buffer.buffer(), buffer.buffer().size());
216 style.addChildElement("text-list-level-style-content", elementContents);
217 }
218
isNumberingStyle() const219 bool KoListStyle::isNumberingStyle() const
220 {
221 QMap<int, KoListLevelProperties>::const_iterator it(d->levels.constBegin());
222 for (; it != d->levels.constEnd(); ++it) {
223 if (isNumberingStyle(it.value().style())) {
224 return true;
225 }
226 }
227 return false;
228 }
229
isNumberingStyle(int style)230 bool KoListStyle::isNumberingStyle(int style)
231 {
232 bool retval = true;
233 switch (style) {
234 case KoListStyle::SquareItem:
235 case KoListStyle::DiscItem:
236 case KoListStyle::CircleItem:
237 case KoListStyle::None:
238 case KoListStyle::Bullet:
239 case KoListStyle::BlackCircle:
240 case KoListStyle::BoxItem:
241 case KoListStyle::RhombusItem:
242 case KoListStyle::HeavyCheckMarkItem:
243 case KoListStyle::BallotXItem:
244 case KoListStyle::RightArrowItem:
245 case KoListStyle::RightArrowHeadItem:
246 case KoListStyle::CustomCharItem:
247 case KoListStyle::ImageItem:
248 retval = false;
249 break;
250 default:
251 retval = true;
252 }
253 return retval;
254 }
255
isOulineStyle() const256 bool KoListStyle::isOulineStyle() const
257 {
258 QMap<int, KoListLevelProperties>::const_iterator it(d->levels.constBegin());
259 for (; it != d->levels.constEnd(); ++it) {
260 if (it.value().isOutlineList()) {
261 return true;
262 }
263 }
264 return false;
265 }
266
listLevels() const267 QList<int> KoListStyle::listLevels() const
268 {
269 return d->levels.keys();
270 }
271
bulletCharacter(int style)272 int KoListStyle::bulletCharacter(int style)
273 {
274 int bullet;
275 switch (style) {
276 case KoListStyle::Bullet: bullet = 0x2022; break;
277 case KoListStyle::CircleItem: bullet = 0x25CB; break;
278 case KoListStyle::RhombusItem: bullet = 0x25C6; break;
279 case KoListStyle::SquareItem: bullet = 0x25A0; break;
280 case KoListStyle::RightArrowHeadItem: bullet = 0x27A2; break;
281 case KoListStyle::RightArrowItem: bullet = 0x2794; break;
282 case KoListStyle::HeavyCheckMarkItem: bullet = 0x2714; break;
283 case KoListStyle::BallotXItem: bullet = 0x2717; break;
284 case KoListStyle::BlackCircle:
285 case KoListStyle::DiscItem: bullet = 0x25CF; break;
286 default: bullet = 0; break; //empty character
287 }
288 return bullet;
289 }
290