]> git.lyx.org Git - lyx.git/blob - src/frontends/qt3/QToc.C
0d35533166a594635039f8c9cc089d518f9c6d94
[lyx.git] / src / frontends / qt3 / QToc.C
1 /**
2  * \file QToc.C
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  *
8  * Full author contact details are available in file CREDITS.
9  */
10
11 #include <config.h>
12
13 #include "QToc.h"
14 #include "QTocDialog.h"
15 #include "Qt2BC.h"
16 #include "qt_helpers.h"
17
18 #include "debug.h"
19
20 #include "controllers/ControlToc.h"
21
22 #include <qcombobox.h>
23 #include <qlistview.h>
24 #include <qpushbutton.h>
25
26 #include <stack>
27
28 using std::endl;
29
30 using std::pair;
31 using std::stack;
32 using std::vector;
33 using std::string;
34
35 namespace lyx {
36 namespace frontend {
37
38 typedef QController<ControlToc, QView<QTocDialog> > base_class;
39
40 QToc::QToc(Dialog & parent)
41         : base_class(parent, _("Table of Contents")), depth_(1)
42 {}
43
44
45 void QToc::build_dialog()
46 {
47         dialog_.reset(new QTocDialog(this));
48
49         // Manage the cancel/close button
50         bcview().setCancel(dialog_->closePB);
51         type_ = toc::getType(controller().params().getCmdName());
52         dialog_->enableButtons();
53 }
54
55
56 void QToc::updateType()
57 {
58         dialog_->typeCO->clear();
59
60         vector<string> const & choice = controller().getTypes();
61         string const & type = toc::getType(controller().params().getCmdName());
62
63         for (vector<string>::const_iterator it = choice.begin();
64                 it != choice.end(); ++it) {
65                 string const & guiname = controller().getGuiName(*it);
66                 dialog_->typeCO->insertItem(toqstr(guiname));
67                 if (*it == type) {
68                         dialog_->typeCO->setCurrentItem(it - choice.begin());
69                         setTitle(lyx::from_ascii(guiname));
70                 }
71         }
72         type_ = type;
73         dialog_->enableButtons();
74 }
75
76
77 void QToc::update_contents()
78 {
79         updateType();
80         updateToc(depth_);
81 }
82
83
84 void QToc::updateToc(int newdepth)
85 {
86         vector<string> const & choice = controller().getTypes();
87         string type;
88         if (!choice.empty())
89                 type = choice[dialog_->typeCO->currentItem()];
90         type_ = type;
91         dialog_->enableButtons();
92
93         toc::Toc const & contents = controller().getContents(type);
94
95         // Check if all elements are the same.
96         if (newdepth == depth_ && toclist == contents) {
97                 return;
98         }
99
100         dialog_->tocLV->clear();
101
102         depth_ = newdepth;
103
104         toclist = contents;
105
106         if (toclist.empty())
107                 return;
108
109         dialog_->tocLV->setUpdatesEnabled(false);
110
111         int curdepth = 0;
112         stack<pair<QListViewItem *, QListViewItem *> > istack;
113         QListViewItem * last = 0;
114         QListViewItem * parent = 0;
115         QListViewItem * item;
116         QListViewItem * selected_item = 0;
117         bool multiple = false;
118
119         // Yes, it is this ugly. Two reasons - root items must have
120         // a QListView parent, rather than QListViewItem; and the
121         // TOC can move in and out an arbitrary number of levels
122
123         for (toc::Toc::const_iterator iter = toclist.begin();
124              iter != toclist.end(); ++iter) {
125                 if (iter->depth() == curdepth) {
126                         // insert it after the last one we processed
127                         if (!parent)
128                                 item = (last ? new QListViewItem(dialog_->tocLV,last) : new QListViewItem(dialog_->tocLV));
129                         else
130                                 item = (last ? new QListViewItem(parent,last) : new QListViewItem(parent));
131                 } else if (iter->depth() > curdepth) {
132                         int diff = iter->depth() - curdepth;
133                         // first save old parent and last
134                         while (diff--)
135                                 istack.push(pair< QListViewItem *, QListViewItem * >(parent,last));
136                         item = (last ? new QListViewItem(last) : new QListViewItem(dialog_->tocLV));
137                         parent = last;
138                 } else {
139                         int diff = curdepth - iter->depth();
140                         pair<QListViewItem *, QListViewItem * > top;
141                         // restore context
142                         while (diff--) {
143                                 top = istack.top();
144                                 istack.pop();
145                         }
146                         parent = top.first;
147                         last = top.second;
148                         // insert it after the last one we processed
149                         if (!parent)
150                                 item = (last ? new QListViewItem(dialog_->tocLV,last) : new QListViewItem(dialog_->tocLV));
151                         else
152                                 item = (last ? new QListViewItem(parent,last) : new QListViewItem(parent));
153                 }
154
155                 lyxerr[Debug::GUI]
156                         << "Table of contents\n"
157                         << "Added item " << iter->str()
158                         << " at depth " << iter->depth()
159                         << ", previous sibling \""
160                         << (last ? fromqstr(last->text(0)) : "0")
161                         << "\", parent \""
162                         << (parent ? fromqstr(parent->text(0)) : "0") << '"'
163                         << endl;
164                 item->setText(0, toqstr(iter->str()));
165                 item->setOpen(iter->depth() < depth_);
166                 curdepth = iter->depth();
167                 last = item;
168
169                 // Recognise part past the counter
170                 if (iter->str().substr(iter->str().find(' ') + 1) == text_) {
171                         if (selected_item == 0)
172                                 selected_item = item;
173                         else
174                                 // more than one match
175                                 multiple = true;
176                 }
177         }
178
179         dialog_->tocLV->setUpdatesEnabled(true);
180         dialog_->tocLV->update();
181         if (!multiple) {
182                 dialog_->tocLV->scrollBy(0, selected_item->itemPos()
183                         - dialog_->tocLV->height() / 2);
184                 dialog_->tocLV->setSelected(selected_item, true);
185         }
186         setTitle(qstring_to_ucs4(dialog_->typeCO->currentText()));
187 }
188
189
190 bool QToc::canOutline()
191 {
192         return controller().canOutline(type_);
193 }
194
195
196 void QToc::select(string const & text)
197 {
198         toc::Toc::const_iterator iter = toclist.begin();
199
200         for (; iter != toclist.end(); ++iter) {
201                 if (iter->str() == text)
202                         break;
203         }
204
205         if (iter == toclist.end()) {
206                 lyxerr[Debug::GUI] << "Couldn't find highlighted TOC entry: "
207                         << text << endl;
208                 return;
209         }
210
211         // Lop off counter part and save:
212         text_ = text.substr(text.find(' ') + 1);
213         controller().goTo(*iter);
214 }
215
216
217 void QToc::set_depth(int depth)
218 {
219         if (depth != depth_)
220                 updateToc(depth);
221 }
222
223
224 void QToc::moveup()
225 {
226         controller().outlineUp();
227         updateToc(depth_);
228 }
229
230
231 void QToc::movedn()
232 {
233         controller().outlineDown();
234         updateToc(depth_);
235 }
236
237
238 void QToc::movein()
239 {
240         controller().outlineIn();
241         updateToc(depth_);
242 }
243
244
245 void QToc::moveout()
246 {
247         controller().outlineOut();
248         updateToc(depth_);
249 }
250
251
252 } // namespace frontend
253 } // namespace lyx