1 /* This file is part of the KDE project
2  * Copyright (C) 2008 Thomas Zander <zander@kde.org>
3  * Copyright (C) 2011 C. Boemann <cbo@boemann.dk>
4  * Copyright (C) 2011-2012 Pierre Stirnweiss <pstirnweiss@googlemail.org>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public License
17  * along with this library; see the file COPYING.LIB.  If not, write to
18  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19  * Boston, MA 02110-1301, USA.
20  */
21 #include "StylesModel.h"
22 
23 #include <KoStyleThumbnailer.h>
24 #include <KoStyleManager.h>
25 #include <KoParagraphStyle.h>
26 #include <KoCharacterStyle.h>
27 
28 #include <QImage>
29 #include <QList>
30 #include <QSharedPointer>
31 #include <KisSignalMapper.h>
32 #include <QCollator>
33 
34 #include <klocalizedstring.h>
35 #include <QDebug>
36 
StylesModel(KoStyleManager * manager,AbstractStylesModel::Type modelType,QObject * parent)37 StylesModel::StylesModel(KoStyleManager *manager, AbstractStylesModel::Type modelType, QObject *parent)
38     : AbstractStylesModel(parent)
39     , m_styleManager(0)
40     , m_currentParagraphStyle(0)
41     , m_defaultCharacterStyle(0)
42     , m_styleMapper(new KisSignalMapper(this))
43     , m_provideStyleNone(false)
44 {
45     m_modelType = modelType;
46     setStyleManager(manager);
47     //Create a default characterStyle for the preview of "None" character style
48     if (m_modelType == StylesModel::CharacterStyle) {
49         m_defaultCharacterStyle = new KoCharacterStyle();
50         m_defaultCharacterStyle->setStyleId(NoneStyleId);
51         m_defaultCharacterStyle->setName(i18n("None"));
52         m_defaultCharacterStyle->setFontPointSize(12);
53 
54         m_provideStyleNone = true;
55     }
56 
57     connect(m_styleMapper, SIGNAL(mapped(int)), this, SLOT(updateName(int)));
58 }
59 
~StylesModel()60 StylesModel::~StylesModel()
61 {
62     delete m_currentParagraphStyle;
63     delete m_defaultCharacterStyle;
64 }
65 
index(int row,int column,const QModelIndex & parent) const66 QModelIndex StylesModel::index(int row, int column, const QModelIndex &parent) const
67 {
68     if (row < 0 || column != 0) {
69         return QModelIndex();
70     }
71 
72     if (!parent.isValid()) {
73         if (row >= m_styleList.count()) {
74             return QModelIndex();
75         }
76         return createIndex(row, column, m_styleList[row]);
77     }
78     return QModelIndex();
79 }
80 
parent(const QModelIndex & child) const81 QModelIndex StylesModel::parent(const QModelIndex &child) const
82 {
83     Q_UNUSED(child);
84     return QModelIndex();
85 }
86 
rowCount(const QModelIndex & parent) const87 int StylesModel::rowCount(const QModelIndex &parent) const
88 {
89     if (!parent.isValid()) {
90         return m_styleList.count();
91     }
92     return 0;
93 }
94 
columnCount(const QModelIndex & parent) const95 int StylesModel::columnCount(const QModelIndex &parent) const
96 {
97     Q_UNUSED(parent);
98     return 1;
99 }
100 
data(const QModelIndex & index,int role) const101 QVariant StylesModel::data(const QModelIndex &index, int role) const
102 {
103     if (!index.isValid()) {
104         return QVariant();
105     }
106 
107     int id = (int)index.internalId();
108     switch (role) {
109     case Qt::DisplayRole: {
110         return QVariant();
111     }
112     case Qt::DecorationRole: {
113         if (!m_styleThumbnailer) {
114             return QPixmap();
115         }
116         if (m_modelType == StylesModel::ParagraphStyle) {
117             KoParagraphStyle *paragStyle = m_styleManager->paragraphStyle(id);
118             if (paragStyle) {
119                 return m_styleThumbnailer->thumbnail(paragStyle);
120             }
121             if (!paragStyle && m_draftParStyleList.contains(id)) {
122                 return m_styleThumbnailer->thumbnail(m_draftParStyleList[id]);
123             }
124         } else {
125             KoCharacterStyle *usedStyle = 0;
126             if (id == NoneStyleId) {
127                 usedStyle = static_cast<KoCharacterStyle *>(m_currentParagraphStyle);
128                 if (!usedStyle) {
129                     usedStyle = m_defaultCharacterStyle;
130                 }
131                 usedStyle->setName(i18n("None"));
132                 if (usedStyle->styleId() >= 0) { //if the styleId is NoneStyleId, we are using the default character style
133                     usedStyle->setStyleId(-usedStyle->styleId()); //this style is not managed by the styleManager but its styleId will be used in the thumbnail cache as part of the key.
134                 }
135                 return m_styleThumbnailer->thumbnail(usedStyle);
136             } else {
137                 usedStyle = m_styleManager->characterStyle(id);
138                 if (usedStyle) {
139                     return m_styleThumbnailer->thumbnail(usedStyle, m_currentParagraphStyle);
140                 }
141                 if (!usedStyle && m_draftCharStyleList.contains(id)) {
142                     return m_styleThumbnailer->thumbnail(m_draftCharStyleList[id]);
143                 }
144             }
145         }
146         break;
147     }
148     case Qt::SizeHintRole: {
149         return QVariant(QSize(250, 48));
150     }
151     default: break;
152     };
153     return QVariant();
154 }
155 
flags(const QModelIndex & index) const156 Qt::ItemFlags StylesModel::flags(const QModelIndex &index) const
157 {
158     if (!index.isValid()) {
159         return 0;
160     }
161     return (Qt::ItemIsSelectable | Qt::ItemIsEnabled);
162 }
163 
setCurrentParagraphStyle(int styleId)164 void StylesModel::setCurrentParagraphStyle(int styleId)
165 {
166     if (!m_styleManager || m_currentParagraphStyle == m_styleManager->paragraphStyle(styleId) || !m_styleManager->paragraphStyle(styleId)) {
167         return; //TODO do we create a default paragraphStyle? use the styleManager default?
168     }
169     if (m_currentParagraphStyle) {
170         delete m_currentParagraphStyle;
171         m_currentParagraphStyle = 0;
172     }
173     m_currentParagraphStyle = m_styleManager->paragraphStyle(styleId)->clone();
174 }
175 
setProvideStyleNone(bool provide)176 void StylesModel::setProvideStyleNone(bool provide)
177 {
178     if (m_modelType == StylesModel::CharacterStyle) {
179         m_provideStyleNone = provide;
180     }
181 }
182 
indexOf(const KoCharacterStyle * style) const183 QModelIndex StylesModel::indexOf(const KoCharacterStyle *style) const
184 {
185     if (style) {
186         return createIndex(m_styleList.indexOf(style->styleId()), 0, style->styleId());
187     }
188     else {
189         return QModelIndex();
190     }
191 }
192 
stylePreview(int row,const QSize & size)193 QImage StylesModel::stylePreview(int row, const QSize &size)
194 {
195     if (!m_styleManager || !m_styleThumbnailer) {
196         return QImage();
197     }
198     if (m_modelType == StylesModel::ParagraphStyle) {
199         KoParagraphStyle *usedStyle = 0;
200         usedStyle = m_styleManager->paragraphStyle(index(row).internalId());
201         if (usedStyle) {
202             return m_styleThumbnailer->thumbnail(usedStyle, size);
203         }
204         if (!usedStyle && m_draftParStyleList.contains(index(row).internalId())) {
205             return m_styleThumbnailer->thumbnail(m_draftParStyleList[index(row).internalId()], size);
206         }
207     } else {
208         KoCharacterStyle *usedStyle = 0;
209         if (index(row).internalId() == (quintptr)NoneStyleId) {
210             usedStyle = static_cast<KoCharacterStyle *>(m_currentParagraphStyle);
211             if (!usedStyle) {
212                 usedStyle = m_defaultCharacterStyle;
213             }
214             usedStyle->setName(i18n("None"));
215             if (usedStyle->styleId() >= 0) {
216                 usedStyle->setStyleId(-usedStyle->styleId()); //this style is not managed by the styleManager but its styleId will be used in the thumbnail cache as part of the key.
217             }
218             return m_styleThumbnailer->thumbnail(usedStyle, m_currentParagraphStyle, size);
219         } else {
220             usedStyle = m_styleManager->characterStyle(index(row).internalId());
221             if (usedStyle) {
222                 return m_styleThumbnailer->thumbnail(usedStyle, m_currentParagraphStyle, size);
223             }
224             if (!usedStyle && m_draftCharStyleList.contains(index(row).internalId())) {
225                 return m_styleThumbnailer->thumbnail(m_draftCharStyleList[index(row).internalId()], m_currentParagraphStyle, size);
226             }
227         }
228     }
229     return QImage();
230 }
231 /*
232 QImage StylesModel::stylePreview(QModelIndex &index, const QSize &size)
233 {
234     if (!m_styleManager || !m_styleThumbnailer) {
235         return QImage();
236     }
237     if (m_modelType == StylesModel::ParagraphStyle) {
238         KoParagraphStyle *usedStyle = 0;
239         usedStyle = m_styleManager->paragraphStyle(index.internalId());
240         if (usedStyle) {
241             return m_styleThumbnailer->thumbnail(usedStyle, size);
242         }
243         if (!usedStyle && m_draftParStyleList.contains(index.internalId())) {
244             return m_styleThumbnailer->thumbnail(m_draftParStyleList[index.internalId()], size);
245         }
246     }
247     else {
248         KoCharacterStyle *usedStyle = 0;
249         if (index.internalId() == NoneStyleId) {
250             usedStyle = static_cast<KoCharacterStyle*>(m_currentParagraphStyle);
251             if (!usedStyle) {
252                 usedStyle = m_defaultCharacterStyle;
253             }
254             usedStyle->setName(i18n("None"));
255             if (usedStyle->styleId() >= 0) {
256                 usedStyle->setStyleId(-usedStyle->styleId()); //this style is not managed by the styleManager but its styleId will be used in the thumbnail cache as part of the key.
257             }
258             return m_styleThumbnailer->thumbnail(usedStyle, m_currentParagraphStyle, size);
259         }
260         else {
261             usedStyle = m_styleManager->characterStyle(index.internalId());
262             if (usedStyle) {
263                 return m_styleThumbnailer->thumbnail(usedStyle, m_currentParagraphStyle, size);
264             }
265             if (!usedStyle && m_draftCharStyleList.contains(index.internalId())) {
266                 return m_styleThumbnailer->thumbnail(m_draftCharStyleList[index.internalId()],m_currentParagraphStyle, size);
267             }
268         }
269     }
270     return QImage();
271 }
272 */
setStyleManager(KoStyleManager * sm)273 void StylesModel::setStyleManager(KoStyleManager *sm)
274 {
275     if (sm == m_styleManager) {
276         return;
277     }
278     if (m_styleManager) {
279         disconnect(sm, SIGNAL(styleAdded(KoParagraphStyle*)), this, SLOT(addParagraphStyle(KoParagraphStyle*)));
280         disconnect(sm, SIGNAL(styleAdded(KoCharacterStyle*)), this, SLOT(addCharacterStyle(KoCharacterStyle*)));
281         disconnect(sm, SIGNAL(styleRemoved(KoParagraphStyle*)), this, SLOT(removeParagraphStyle(KoParagraphStyle*)));
282         disconnect(sm, SIGNAL(styleRemoved(KoCharacterStyle*)), this, SLOT(removeCharacterStyle(KoCharacterStyle*)));
283     }
284     m_styleManager = sm;
285     if (m_styleManager == 0) {
286         return;
287     }
288 
289     if (m_modelType == StylesModel::ParagraphStyle) {
290         updateParagraphStyles();
291         connect(sm, SIGNAL(styleAdded(KoParagraphStyle*)), this, SLOT(addParagraphStyle(KoParagraphStyle*)));
292         connect(sm, SIGNAL(styleRemoved(KoParagraphStyle*)), this, SLOT(removeParagraphStyle(KoParagraphStyle*)));
293     } else {
294         updateCharacterStyles();
295         connect(sm, SIGNAL(styleAdded(KoCharacterStyle*)), this, SLOT(addCharacterStyle(KoCharacterStyle*)));
296         connect(sm, SIGNAL(styleRemoved(KoCharacterStyle*)), this, SLOT(removeCharacterStyle(KoCharacterStyle*)));
297     }
298 }
299 
setStyleThumbnailer(KoStyleThumbnailer * thumbnailer)300 void StylesModel::setStyleThumbnailer(KoStyleThumbnailer *thumbnailer)
301 {
302     m_styleThumbnailer = thumbnailer;
303 }
304 
305 // called when the stylemanager adds a style
addParagraphStyle(KoParagraphStyle * style)306 void StylesModel::addParagraphStyle(KoParagraphStyle *style)
307 {
308     Q_ASSERT(style);
309     QCollator collator;
310     QList<int>::iterator begin = m_styleList.begin();
311     int index = 0;
312     for (; begin != m_styleList.end(); ++begin) {
313         KoParagraphStyle *s = m_styleManager->paragraphStyle(*begin);
314         if (!s && m_draftParStyleList.contains(*begin)) {
315             s = m_draftParStyleList[*begin];
316         }
317         // s should be found as the manager and the m_styleList should be in sync
318         Q_ASSERT(s);
319         if (collator.compare(style->name(), s->name()) < 0) {
320             break;
321         }
322         ++index;
323     }
324     beginInsertRows(QModelIndex(), index, index);
325     m_styleList.insert(begin, style->styleId());
326     m_styleMapper->setMapping(style, style->styleId());
327     connect(style, SIGNAL(nameChanged(QString)), m_styleMapper, SLOT(map()));
328     endInsertRows();
329 }
330 
sortParagraphStyleByName(KoParagraphStyle * style1,KoParagraphStyle * style2)331 bool sortParagraphStyleByName(KoParagraphStyle *style1, KoParagraphStyle *style2)
332 {
333     Q_ASSERT(style1);
334     Q_ASSERT(style2);
335     return QCollator().compare(style1->name(), style2->name()) < 0;
336 }
337 
updateParagraphStyles()338 void StylesModel::updateParagraphStyles()
339 {
340     Q_ASSERT(m_styleManager);
341 
342     beginResetModel();
343     m_styleList.clear();
344 
345     QList<KoParagraphStyle *> styles = m_styleManager->paragraphStyles();
346     std::sort(styles.begin(), styles.end(), sortParagraphStyleByName);
347 
348     Q_FOREACH (KoParagraphStyle *style, styles) {
349         if (style != m_styleManager->defaultParagraphStyle()) { //The default character style is not user selectable. It only provides individual property defaults and is not a style per say.
350             m_styleList.append(style->styleId());
351             m_styleMapper->setMapping(style, style->styleId());
352             connect(style, SIGNAL(nameChanged(QString)), m_styleMapper, SLOT(map()));
353         }
354     }
355 
356     endResetModel();
357 }
358 
359 // called when the stylemanager adds a style
addCharacterStyle(KoCharacterStyle * style)360 void StylesModel::addCharacterStyle(KoCharacterStyle *style)
361 {
362     Q_ASSERT(style);
363     // find the place where we need to insert the style
364     QCollator collator;
365     QList<int>::iterator begin = m_styleList.begin();
366     int index = 0;
367     // the None style should also be the first one so only start after it
368     if (begin != m_styleList.end() && *begin == NoneStyleId) {
369         ++begin;
370         ++index;
371     }
372     for (; begin != m_styleList.end(); ++begin) {
373         KoCharacterStyle *s = m_styleManager->characterStyle(*begin);
374         if (!s && m_draftCharStyleList.contains(*begin)) {
375             s = m_draftCharStyleList[*begin];
376         }
377         // s should be found as the manager and the m_styleList should be in sync
378         Q_ASSERT(s);
379         if (collator.compare(style->name(), s->name()) < 0) {
380             break;
381         }
382         ++index;
383     }
384     beginInsertRows(QModelIndex(), index, index);
385     m_styleList.insert(index, style->styleId());
386     endInsertRows();
387     m_styleMapper->setMapping(style, style->styleId());
388     connect(style, SIGNAL(nameChanged(QString)), m_styleMapper, SLOT(map()));
389 }
390 
sortCharacterStyleByName(KoCharacterStyle * style1,KoCharacterStyle * style2)391 bool sortCharacterStyleByName(KoCharacterStyle *style1, KoCharacterStyle *style2)
392 {
393     Q_ASSERT(style1);
394     Q_ASSERT(style2);
395     return QCollator().compare(style1->name(), style2->name()) < 0;
396 }
397 
updateCharacterStyles()398 void StylesModel::updateCharacterStyles()
399 {
400     Q_ASSERT(m_styleManager);
401 
402     beginResetModel();
403     m_styleList.clear();
404 
405     if (m_provideStyleNone && m_styleManager->paragraphStyles().count()) {
406         m_styleList.append(NoneStyleId);
407     }
408 
409     QList<KoCharacterStyle *> styles = m_styleManager->characterStyles();
410     std::sort(styles.begin(), styles.end(), sortCharacterStyleByName);
411 
412     Q_FOREACH (KoCharacterStyle *style, styles) {
413         if (style != m_styleManager->defaultCharacterStyle()) { //The default character style is not user selectable. It only provides individual property defaults and is not a style per say.
414             m_styleList.append(style->styleId());
415             m_styleMapper->setMapping(style, style->styleId());
416             connect(style, SIGNAL(nameChanged(QString)), m_styleMapper, SLOT(map()));
417         }
418     }
419 
420     endResetModel();
421 }
422 
423 // called when the stylemanager removes a style
removeParagraphStyle(KoParagraphStyle * style)424 void StylesModel::removeParagraphStyle(KoParagraphStyle *style)
425 {
426     int row = m_styleList.indexOf(style->styleId());
427     beginRemoveRows(QModelIndex(), row, row);
428     m_styleMapper->removeMappings(style);
429     disconnect(style, SIGNAL(nameChanged(QString)), m_styleMapper, SLOT(map()));
430     m_styleList.removeAt(row);
431     endRemoveRows();
432 }
433 
434 // called when the stylemanager removes a style
removeCharacterStyle(KoCharacterStyle * style)435 void StylesModel::removeCharacterStyle(KoCharacterStyle *style)
436 {
437     int row = m_styleList.indexOf(style->styleId());
438     beginRemoveRows(QModelIndex(), row, row);
439     m_styleMapper->removeMappings(style);
440     disconnect(style, SIGNAL(nameChanged(QString)), m_styleMapper, SLOT(map()));
441     m_styleList.removeAt(row);
442     endRemoveRows();
443 }
444 
updateName(int styleId)445 void StylesModel::updateName(int styleId)
446 {
447     // updating the name of a style can mean that the style needs to be moved inside the list to keep the sort order.
448     QCollator collator;
449     int oldIndex = m_styleList.indexOf(styleId);
450     if (oldIndex >= 0) {
451         int newIndex = 0;
452         if (m_modelType == StylesModel::ParagraphStyle) {
453             KoParagraphStyle *paragStyle = m_styleManager->paragraphStyle(styleId);
454             if (!paragStyle && m_draftParStyleList.contains(styleId)) {
455                 paragStyle = m_draftParStyleList.value(styleId);
456             }
457             if (paragStyle) {
458                 m_styleThumbnailer->removeFromCache(paragStyle);
459 
460                 QList<int>::iterator begin = m_styleList.begin();
461                 for (; begin != m_styleList.end(); ++begin) {
462                     // don't test again the same style
463                     if (*begin == styleId) {
464                         continue;
465                     }
466                     KoParagraphStyle *s = m_styleManager->paragraphStyle(*begin);
467                     if (!s && m_draftParStyleList.contains(*begin)) {
468                         s = m_draftParStyleList[*begin];
469                     }
470                     // s should be found as the manager and the m_styleList should be in sync
471                     Q_ASSERT(s);
472                     if (collator.compare(paragStyle->name(), s->name()) < 0) {
473                         break;
474                     }
475                     ++newIndex;
476                 }
477                 if (oldIndex != newIndex) {
478                     // beginMoveRows needs the index where it would be placed when it is still in the old position
479                     // so add one when newIndex > oldIndex
480                     beginMoveRows(QModelIndex(), oldIndex, oldIndex, QModelIndex(), newIndex > oldIndex ? newIndex + 1 : newIndex);
481                     m_styleList.removeAt(oldIndex);
482                     m_styleList.insert(newIndex, styleId);
483                     endMoveRows();
484                 }
485             }
486         } else {
487             KoCharacterStyle *characterStyle = m_styleManager->characterStyle(styleId);
488             if (!characterStyle && m_draftCharStyleList.contains(styleId)) {
489                 characterStyle = m_draftCharStyleList[styleId];
490             }
491             if (characterStyle) {
492                 m_styleThumbnailer->removeFromCache(characterStyle);
493 
494                 QList<int>::iterator begin = m_styleList.begin();
495                 if (begin != m_styleList.end() && *begin == NoneStyleId) {
496                     ++begin;
497                     ++newIndex;
498                 }
499                 for (; begin != m_styleList.end(); ++begin) {
500                     // don't test again the same style
501                     if (*begin == styleId) {
502                         continue;
503                     }
504                     KoCharacterStyle *s = m_styleManager->characterStyle(*begin);
505                     if (!s && m_draftCharStyleList.contains(*begin)) {
506                         s = m_draftCharStyleList[*begin];
507                     }
508                     // s should be found as the manager and the m_styleList should be in sync
509                     Q_ASSERT(s);
510                     if (collator.compare(characterStyle->name(), s->name()) < 0) {
511                         break;
512                     }
513                     ++newIndex;
514                 }
515                 if (oldIndex != newIndex) {
516                     // beginMoveRows needs the index where it would be placed when it is still in the old position
517                     // so add one when newIndex > oldIndex
518                     beginMoveRows(QModelIndex(), oldIndex, oldIndex, QModelIndex(), newIndex > oldIndex ? newIndex + 1 : newIndex);
519                     m_styleList.removeAt(oldIndex);
520                     m_styleList.insert(newIndex, styleId);
521                     endMoveRows();
522                 }
523             }
524         }
525     }
526 }
527 
firstStyleIndex()528 QModelIndex StylesModel::firstStyleIndex()
529 {
530     if (!m_styleList.count()) {
531         return QModelIndex();
532     }
533     return createIndex(m_styleList.indexOf(m_styleList.at(0)), 0, m_styleList.at(0));
534 }
535 
StyleList()536 QList<int> StylesModel::StyleList()
537 {
538     return m_styleList;
539 }
540 
draftParStyleList()541 QHash<int, KoParagraphStyle *> StylesModel::draftParStyleList()
542 {
543     return m_draftParStyleList;
544 }
545 
draftCharStyleList()546 QHash<int, KoCharacterStyle *> StylesModel::draftCharStyleList()
547 {
548     return m_draftCharStyleList;
549 }
550 
addDraftParagraphStyle(KoParagraphStyle * style)551 void StylesModel::addDraftParagraphStyle(KoParagraphStyle *style)
552 {
553     style->setStyleId(-(m_draftParStyleList.count() + 1));
554     m_draftParStyleList.insert(style->styleId(), style);
555     addParagraphStyle(style);
556 }
557 
addDraftCharacterStyle(KoCharacterStyle * style)558 void StylesModel::addDraftCharacterStyle(KoCharacterStyle *style)
559 {
560     if (m_draftCharStyleList.count() == 0) { // we have a character style "m_defaultCharacterStyle" with style id NoneStyleId in style model.
561         style->setStyleId(-(m_draftCharStyleList.count() + 2));
562     } else {
563         style->setStyleId(-(m_draftCharStyleList.count() + 1));
564     }
565     m_draftCharStyleList.insert(style->styleId(), style);
566     addCharacterStyle(style);
567 }
568 
clearDraftStyles()569 void StylesModel::clearDraftStyles()
570 {
571     Q_FOREACH (KoParagraphStyle *style, m_draftParStyleList.values()) {
572         removeParagraphStyle(style);
573     }
574     m_draftParStyleList.clear();
575     Q_FOREACH (KoCharacterStyle *style, m_draftCharStyleList.values()) {
576         removeCharacterStyle(style);
577     }
578     m_draftCharStyleList.clear();
579 }
580 
stylesType() const581 StylesModel::Type StylesModel::stylesType() const
582 {
583     return m_modelType;
584 }
585