]> git.lyx.org Git - lyx.git/blob - src/frontends/qt4/TocModel.cpp
a78f2ae325f1c3de8a1b0d6517c5ee72a5b19a2e
[lyx.git] / src / frontends / qt4 / TocModel.cpp
1 /**
2  * \file TocModel.cpp
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author John Levon
7  * \author Abdelrazak Younes
8  *
9  * Full author contact details are available in file CREDITS.
10  */
11
12 #include <config.h>
13
14 #include "TocModel.h"
15
16 #include "Buffer.h"
17 #include "BufferView.h"
18 #include "Cursor.h"
19 #include "DocIterator.h"
20 #include "FuncRequest.h"
21 #include "LyXFunc.h"
22 #include "TocBackend.h"
23
24 #include "support/convert.h"
25 #include "support/debug.h"
26 #include "support/lassert.h"
27
28 #include <QSortFilterProxyModel>
29
30 #include <climits>
31
32 using namespace std;
33
34 namespace lyx {
35 namespace frontend {
36
37 ///////////////////////////////////////////////////////////////////////////////
38 //
39 // TocTypeModel
40 //
41 ///////////////////////////////////////////////////////////////////////////////
42
43 TocTypeModel::TocTypeModel(QObject * parent)
44         : QStandardItemModel(parent)
45 {
46 }
47
48
49 void TocTypeModel::reset()
50 {
51         QStandardItemModel::reset();
52 }
53
54
55 ///////////////////////////////////////////////////////////////////////////////
56 //
57 // TocModel
58 //
59 ///////////////////////////////////////////////////////////////////////////////
60
61 TocModel::TocModel(QObject * parent)
62         : model_(new TocTypeModel(parent)),
63         sorted_model_(new QSortFilterProxyModel(parent)),
64         is_sorted_(false), maxdepth_(0), mindepth_(0)
65 {
66 #if QT_VERSION >= 0x040300
67         sorted_model_->setSortLocaleAware(true);
68 #endif
69         sorted_model_->setSourceModel(model_);
70 }
71
72
73 QAbstractItemModel * TocModel::model()
74 {
75         if (is_sorted_)
76                 return sorted_model_;
77         return model_;
78 }
79
80
81 QAbstractItemModel const * TocModel::model() const
82 {
83         if (is_sorted_)
84                 return sorted_model_;
85         return model_;
86 }
87
88
89 void TocModel::clear()
90 {
91         model_->blockSignals(true);
92         model_->clear();
93         model_->blockSignals(false);
94 }
95
96
97 void TocModel::sort(bool sort_it)
98 {
99         is_sorted_ = sort_it;
100         if (is_sorted_)
101                 sorted_model_->sort(0);
102 }
103
104
105 TocItem const & TocModel::tocItem(QModelIndex const & index) const
106 {
107         return (*toc_)[model()->data(index, Qt::UserRole).toUInt()];
108 }
109
110
111 QModelIndex TocModel::modelIndex(DocIterator const & dit) const
112 {
113         if (toc_->empty())
114                 return QModelIndex();
115
116         unsigned int const toc_index = toc_->item(dit) - toc_->begin();
117
118         QModelIndexList list = model()->match(model()->index(0, 0), Qt::UserRole,
119                 QVariant(toc_index), 1,
120                 Qt::MatchFlags(Qt::MatchExactly | Qt::MatchRecursive));
121
122         LASSERT(!list.isEmpty(), return QModelIndex());
123         return list[0];
124 }
125
126
127 void TocModel::reset()
128 {
129         model_->reset();
130 }
131
132
133 void TocModel::updateItem(DocIterator const & dit)
134 {
135         QModelIndex index = modelIndex(dit);
136         TocItem const & toc_item = tocItem(index);
137         model_->setData(index, toqstr(toc_item.str()), Qt::DisplayRole);
138 }
139
140
141 void TocModel::reset(Toc const & toc)
142 {
143         toc_ = &toc;
144         if (toc_->empty()) {
145                 maxdepth_ = 0;
146                 mindepth_ = 0;
147                 reset();
148                 return;
149         }
150
151         model_->blockSignals(true);
152         model_->insertColumns(0, 1);
153         maxdepth_ = 0;
154         mindepth_ = INT_MAX;
155
156         size_t end = toc_->size();
157         for (unsigned int index = 0; index != end; ++index) {
158                 TocItem const & item = (*toc_)[index];
159                 maxdepth_ = max(maxdepth_, item.depth());
160                 mindepth_ = min(mindepth_, item.depth());
161                 int current_row = model_->rowCount();
162                 model_->insertRows(current_row, 1);
163                 QModelIndex top_level_item = model_->index(current_row, 0);
164                 model_->setData(top_level_item, toqstr(item.str()), Qt::DisplayRole);
165                 model_->setData(top_level_item, index, Qt::UserRole);
166
167                 LYXERR(Debug::GUI, "Toc: at depth " << item.depth()
168                         << ", added item " << item.str());
169
170                 populate(index, top_level_item);
171                 if (index >= end)
172                         break;
173         }
174
175         model_->setHeaderData(0, Qt::Horizontal, QVariant("title"), Qt::DisplayRole);
176         if (is_sorted_)
177                 sorted_model_->sort(0);
178         model_->blockSignals(false);
179         reset();
180 //      emit headerDataChanged();
181 }
182
183
184 void TocModel::populate(unsigned int & index, QModelIndex const & parent)
185 {
186         int curdepth = (*toc_)[index].depth() + 1;
187
188         int current_row;
189         QModelIndex child_item;
190         model_->insertColumns(0, 1, parent);
191
192         size_t end = toc_->size();
193         ++index;
194         for (; index != end; ++index) {
195                 TocItem const & item = (*toc_)[index];
196                 if (item.depth() < curdepth) {
197                         --index;
198                         return;
199                 }
200                 maxdepth_ = max(maxdepth_, item.depth());
201                 mindepth_ = min(mindepth_, item.depth());
202                 current_row = model_->rowCount(parent);
203                 model_->insertRows(current_row, 1, parent);
204                 child_item = model_->index(current_row, 0, parent);
205                 model_->setData(child_item, toqstr(item.str()), Qt::DisplayRole);
206                 model_->setData(child_item, index, Qt::UserRole);
207                 populate(index, child_item);
208                 if (index >= end)
209                         break;
210         }
211 }
212
213
214 int TocModel::modelDepth() const
215 {
216         int const d = maxdepth_ - mindepth_;
217         LASSERT(d >= 0 && d <= 100, return 0);
218         return d;
219 }
220
221
222 ///////////////////////////////////////////////////////////////////////////////
223 //
224 // TocModels
225 //
226 ///////////////////////////////////////////////////////////////////////////////
227
228 TocModels::TocModels()
229         : bv_(0)
230 {
231         names_ = new TocTypeModel(this);
232         names_sorted_ = new QSortFilterProxyModel(this);
233         names_sorted_->setSourceModel(names_);
234 #if QT_VERSION >= 0x040300
235         names_sorted_->setSortLocaleAware(true);
236 #endif
237         names_sorted_->sort(0);
238 }
239
240
241 void TocModels::clear() 
242 {
243         names_->blockSignals(true);
244         names_->clear();
245         names_->blockSignals(false);
246         iterator end = models_.end();
247         for (iterator it = models_.begin(); it != end;  ++it)
248                 it.value()->clear();
249 }
250
251
252 int TocModels::depth(QString const & type)
253 {
254         const_iterator it = models_.find(type);
255         if (!bv_ || it == models_.end())
256                 return 0;
257         return it.value()->modelDepth();
258 }
259
260
261 QAbstractItemModel * TocModels::model(QString const & type)
262 {
263         if (!bv_)
264                 return 0;
265         iterator it = models_.find(type);
266         if (it != models_.end())
267                 return it.value()->model();
268         LYXERR0("type not found: " << type);
269         return 0;
270 }
271
272
273 QAbstractItemModel * TocModels::nameModel()
274 {
275         return names_sorted_;
276 }
277
278
279 QModelIndex TocModels::currentIndex(QString const & type) const
280 {
281         const_iterator it = models_.find(type);
282         if (!bv_ || it == models_.end())
283                 return QModelIndex();
284         return it.value()->modelIndex(bv_->cursor());
285 }
286
287
288 void TocModels::goTo(QString const & type, QModelIndex const & index) const
289 {
290         const_iterator it = models_.find(type);
291         if (it == models_.end() || !index.isValid()) {
292                 LYXERR(Debug::GUI, "TocModels::goTo(): QModelIndex is invalid!");
293                 return;
294         }
295         LASSERT(index.model() == it.value()->model(), return);
296         TocItem const item = it.value()->tocItem(index);
297         LYXERR(Debug::GUI, "TocModels::goTo " << item.str());
298         dispatch(item.action());
299 }
300
301
302 TocItem const TocModels::currentItem(QString const & type,
303         QModelIndex const & index) const
304 {
305         const_iterator it = models_.find(type);
306         if (it == models_.end() || !index.isValid()) {
307                 LYXERR(Debug::GUI, "TocModels::currentItem(): QModelIndex is invalid!");
308                 return TocItem();
309         }
310         LASSERT(index.model() == it.value()->model(), return TocItem());
311         
312         return it.value()->tocItem(index);
313 }
314  
315
316 void TocModels::updateBackend() const
317 {
318         bv_->buffer().masterBuffer()->tocBackend().update();
319         bv_->buffer().structureChanged();
320 }
321
322
323 void TocModels::updateItem(QString const & type, DocIterator const & dit)
324 {
325         models_[type]->updateItem(dit);
326 }
327
328
329 void TocModels::reset(BufferView const * bv)
330 {
331         bv_ = bv;
332         clear();
333         if (!bv_) {
334                 iterator end = models_.end();
335                 for (iterator it = models_.begin(); it != end;  ++it)
336                         it.value()->reset();
337                 names_->reset();
338                 return;
339         }
340
341         names_->blockSignals(true);
342         names_->insertColumns(0, 1);
343         TocList const & tocs = bv_->buffer().masterBuffer()->tocBackend().tocs();
344         TocList::const_iterator it = tocs.begin();
345         TocList::const_iterator toc_end = tocs.end();
346         for (; it != toc_end; ++it) {
347                 QString const type = toqstr(it->first);
348
349                 // First, fill in the toc models.
350                 iterator mod_it = models_.find(type);
351                 if (mod_it == models_.end())
352                         mod_it = models_.insert(type, new TocModel(this));
353                 mod_it.value()->reset(it->second);
354
355                 // Fill in the names_ model.
356                 QString const gui_name = guiName(it->first, bv->buffer().params());
357                 int const current_row = names_->rowCount();
358                 names_->insertRows(current_row, 1);
359                 QModelIndex const index = names_->index(current_row, 0);
360                 names_->setData(index, gui_name, Qt::DisplayRole);
361                 names_->setData(index, type, Qt::UserRole);
362         }
363         names_->blockSignals(false);
364         names_->reset();
365 }
366
367
368 bool TocModels::isSorted(QString const & type) const
369 {
370         const_iterator it = models_.find(type);
371         if (it == models_.end()) {
372                 LYXERR0("type not found: " << type);
373                 return false;
374         }
375         return it.value()->isSorted();
376 }
377
378
379 void TocModels::sort(QString const & type, bool sort_it)
380 {
381         iterator it = models_.find(type);
382         if (it == models_.end())
383                 LYXERR0("type not found: " << type);
384         else
385                 it.value()->sort(sort_it);
386 }
387
388 } // namespace frontend
389 } // namespace lyx
390
391 #include "moc_TocModel.cpp"