1 #ifndef KOSECTIONMODEL_H 2 #define KOSECTIONMODEL_H 3 4 #include <QTextDocument> 5 #include <QAbstractItemModel> 6 #include <QVector> 7 #include <QSet> 8 9 #include <KoSection.h> 10 #include <KoSectionEnd.h> 11 12 /** 13 * Used to handle all the sections in the document 14 * 15 * Now there actually two levels of section handling: 16 * 1) Formatting Level: on this level we should be sure, that 17 * pointers to KoSection and KoSectionEnd in the KoParagraphStyles 18 * properties SectionEndings and SectionStartings are consistent. 19 * Handling on this level is provided on the level of text editing 20 * commands: DeleteCommand, NewSectionCommand 21 * We can't move it to another place, because we should know the 22 * semantics of operation to handle it right way. 23 * 2) Model(Tree) Level: on this level we should update KoSectionModel 24 * right way, so it in any moment represents the actual tree 25 * of sections. Tree is built easily: 26 * One section is son of another, if it is directly nested in it. 27 * As text editing commands have access to change Formatting Level, 28 * they are declared as friend classes of KoSectionModel to be able 29 * affect Model structure without changing something on Formatting 30 * Level. Also affected by RenameSectionCommand. 31 * 32 * Also we need to look at the consistency of some section properties: 33 * 34 * 1) Bounds. Those now are handled with QTextCursors that are placed 35 * on start and end of the section. In default state start cursor 36 * isn't moving if text inserted in its position, and end cursor 37 * moves. But in the case of initial document loading, it is necessary 38 * to make some end cursors stop moving, so we have: 39 * KoTextLoader -> calling -> KoSection::setKeepEndBound() 40 * KoTextLoader -> calling -> KoSectionModel::allowMovingEndBound() 41 * ^-- this needed to restore default behaviour after load 42 * 43 * 2) Level. Level means the depth of the section in tree. Root 44 * sections has 0 (zero) level. Now if you look at the possible 45 * text editing command affecting sections you may notice that 46 * level of section doesn't change in any case. Initial level 47 * is set in KoSection constructor as parent's level plus one. 48 * TODO: write about drag-n-drop here, when its implemented 49 * 50 * 3) Name. Each KoSection has a name that must be unique. We have 51 * two groups of KoSections in each moment of time: the first group 52 * consists of the sections that are present in document now, 53 * the second group consists of the sections that were deleted, but 54 * we still need them as they may be restored with "undo". 55 * This groups are stored in m_registeredSections and m_sectionNames. 56 * 57 * Sections are created through this newSection() and newSectionEnd() 58 * functions. 59 * 60 * This object is created for QTextDocument on the first query of it. 61 */ 62 class KOTEXT_EXPORT KoSectionModel : public QAbstractItemModel 63 { 64 Q_OBJECT 65 public: 66 static const int PointerRole = Qt::UserRole; 67 68 explicit KoSectionModel(QTextDocument *doc); 69 ~KoSectionModel() override; 70 71 QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override; 72 QModelIndex parent(const QModelIndex &child) const override; 73 74 int rowCount(const QModelIndex &parent = QModelIndex()) const override; 75 int columnCount(const QModelIndex &parent = QModelIndex()) const override; 76 77 QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; 78 79 /// Creates KoSection in position of @p cursor with some allowed name 80 KoSection *createSection(const QTextCursor &cursor, KoSection *parent); 81 82 /// Creates KoSection in position of @p cursor with specified @p name 83 KoSection *createSection(const QTextCursor &cursor, KoSection *parent, const QString &name); 84 85 /// Creates KoSectionEnd in pair for a @p section 86 KoSectionEnd *createSectionEnd(KoSection *section); 87 88 /** Tries to set @p section name to @p name 89 * @return @c false if there is a section with such name 90 * and new name isn't accepted and @c true otherwise. 91 */ 92 bool setName(KoSection *section, const QString &name); 93 94 /** 95 * Returns pointer to the deepest KoSection that covers @p pos 96 * or NULL if there is no such section 97 */ 98 KoSection *sectionAtPosition(int pos) const; 99 100 /// Returns name for the new section. 101 QString possibleNewName(); 102 103 /// Returns if this name is possible. 104 bool isValidNewName(const QString &name) const; 105 106 /// Setting all sections end bound cursor to move with text inserting. 107 void allowMovingEndBound(); 108 109 /// Finds index of @p child inside his parent. 110 int findRowOfChild(KoSection *child) const; 111 112 private: 113 Q_DISABLE_COPY(KoSectionModel) 114 115 friend class DeleteCommand; 116 friend class NewSectionCommand; 117 118 /** 119 * Inserts @p section to it's parent (should be 120 * stored in @p section already) in position childIdx. 121 * Affects only Model Level(@see KoSectionModel). 122 */ 123 void insertToModel(KoSection* section, int childIdx); 124 /** 125 * Deletes @p section from it's parent (should be 126 * stored in @p section already). 127 * Affects only Model Level 128 * @see KoSectionModel 129 */ 130 void deleteFromModel(KoSection *section); 131 132 QTextDocument *m_doc; 133 QSet<KoSection *> m_registeredSections; ///< stores pointer to sections that sometime was registered 134 QHash<QString, KoSection *> m_sectionNames; ///< stores name -> pointer reference, for sections that are visible in document now 135 QHash<KoSection *, QPersistentModelIndex> m_modelIndex; 136 137 QVector<KoSection *> m_rootSections; 138 139 }; 140 141 Q_DECLARE_METATYPE(KoSectionModel *) 142 143 #endif //KOSECTIONMODEL_H 144