]> git.lyx.org Git - lyx.git/blob - src/frontends/qt4/GuiRef.cpp
* fix spelling in comments to please John.
[lyx.git] / src / frontends / qt4 / GuiRef.cpp
1 /**
2  * \file GuiRef.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 Jürgen Spitzmüller
8  *
9  * Full author contact details are available in file CREDITS.
10  */
11
12 #include <config.h>
13
14 #include "GuiRef.h"
15
16 #include "Buffer.h"
17 #include "BufferList.h"
18 #include "FuncRequest.h"
19
20 #include "qt_helpers.h"
21
22 #include "insets/InsetRef.h"
23
24 #include "support/FileName.h"
25 #include "support/FileNameList.h"
26 #include "support/filetools.h" // makeAbsPath, makeDisplayPath
27
28 #include <QLineEdit>
29 #include <QCheckBox>
30 #include <QListWidget>
31 #include <QListWidgetItem>
32 #include <QPushButton>
33 #include <QToolTip>
34 #include <QCloseEvent>
35
36 using namespace std;
37 using namespace lyx::support;
38
39 namespace lyx {
40 namespace frontend {
41
42 GuiRef::GuiRef(GuiView & lv)
43         : GuiDialog(lv, "ref", qt_("Cross-reference")),
44           params_(insetCode("ref"))
45 {
46         setupUi(this);
47
48         at_ref_ = false;
49
50         // Enabling is set in updateRefs. Disable for now in case no
51         // call to updateContents follows (e.g. read-only documents).
52         sortCB->setEnabled(false);
53         caseSensitiveCB->setEnabled(false);
54         caseSensitiveCB->setChecked(false);
55         refsLW->setEnabled(false);
56         gotoPB->setEnabled(false);
57
58         connect(okPB, SIGNAL(clicked()), this, SLOT(slotOK()));
59         connect(applyPB, SIGNAL(clicked()), this, SLOT(slotApply()));
60         connect(closePB, SIGNAL(clicked()), this, SLOT(slotClose()));
61         connect(closePB, SIGNAL(clicked()), this, SLOT(resetDialog()));
62         connect(this, SIGNAL(rejected()), this, SLOT(dialogRejected()));
63
64         connect(typeCO, SIGNAL(activated(int)),
65                 this, SLOT(changed_adaptor()));
66         connect(referenceED, SIGNAL(textChanged(QString)),
67                 this, SLOT(changed_adaptor()));
68         connect(nameED, SIGNAL(textChanged(QString)),
69                 this, SLOT(changed_adaptor()));
70         connect(refsLW, SIGNAL(itemClicked(QListWidgetItem *)),
71                 this, SLOT(refHighlighted(QListWidgetItem *)));
72         connect(refsLW, SIGNAL(itemSelectionChanged()),
73                 this, SLOT(selectionChanged()));
74         connect(refsLW, SIGNAL(itemDoubleClicked(QListWidgetItem *)),
75                 this, SLOT(refSelected(QListWidgetItem *)));
76         connect(sortCB, SIGNAL(clicked()),
77                 this, SLOT(sortToggled()));
78         connect(caseSensitiveCB, SIGNAL(clicked()),
79                 this, SLOT(caseSensitiveToggled()));
80         connect(gotoPB, SIGNAL(clicked()),
81                 this, SLOT(gotoClicked()));
82         connect(updatePB, SIGNAL(clicked()),
83                 this, SLOT(updateClicked()));
84         connect(bufferCO, SIGNAL(activated(int)),
85                 this, SLOT(updateClicked()));
86
87         bc().setPolicy(ButtonPolicy::NoRepeatedApplyReadOnlyPolicy);
88         bc().setOK(okPB);
89         bc().setApply(applyPB);
90         bc().setCancel(closePB);
91         bc().addReadOnly(refsLW);
92         bc().addReadOnly(sortCB);
93         bc().addReadOnly(caseSensitiveCB);
94         bc().addReadOnly(nameED);
95         bc().addReadOnly(referenceED);
96         bc().addReadOnly(typeCO);
97         bc().addReadOnly(bufferCO);
98
99         restored_buffer_ = -1;
100         active_buffer_ = -1;
101 }
102
103
104 void GuiRef::changed_adaptor()
105 {
106         changed();
107 }
108
109
110 void GuiRef::gotoClicked()
111 {
112         gotoRef();
113 }
114
115
116 void GuiRef::selectionChanged()
117 {
118         if (isBufferReadonly())
119                 return;
120
121         QList<QListWidgetItem *> selections = refsLW->selectedItems();
122         if (selections.isEmpty())
123                 return;
124         QListWidgetItem * sel = selections.first();
125         refHighlighted(sel);
126         return;
127 }
128
129
130 void GuiRef::refHighlighted(QListWidgetItem * sel)
131 {
132         if (isBufferReadonly())
133                 return;
134
135 /*      int const cur_item = refsLW->currentRow();
136         bool const cur_item_selected = cur_item >= 0 ?
137                 refsLB->isSelected(cur_item) : false;*/
138         bool const cur_item_selected = refsLW->isItemSelected(sel);
139
140         if (cur_item_selected)
141                 referenceED->setText(sel->text());
142
143         if (at_ref_)
144                 gotoRef();
145         gotoPB->setEnabled(true);
146         if (typeAllowed())
147                 typeCO->setEnabled(true);
148         if (nameAllowed())
149                 nameED->setEnabled(true);
150 }
151
152
153 void GuiRef::refSelected(QListWidgetItem * sel)
154 {
155         if (isBufferReadonly())
156                 return;
157
158 /*      int const cur_item = refsLW->currentRow();
159         bool const cur_item_selected = cur_item >= 0 ?
160                 refsLB->isSelected(cur_item) : false;*/
161         bool const cur_item_selected = refsLW->isItemSelected(sel);
162
163         if (cur_item_selected)
164                 referenceED->setText(sel->text());
165         // <enter> or double click, inserts ref and closes dialog
166         slotOK();
167 }
168
169
170 void GuiRef::sortToggled()
171 {
172         caseSensitiveCB->setEnabled(sortCB->isChecked());
173         redoRefs();
174 }
175
176
177 void GuiRef::caseSensitiveToggled()
178 {
179         redoRefs();
180 }
181
182
183 void GuiRef::updateClicked()
184 {
185         updateRefs();
186 }
187
188
189 void GuiRef::dialogRejected()
190 {
191         resetDialog();
192         // We have to do this manually, instead of calling slotClose(), because
193         // the dialog has already been made invisible before rejected() triggers.
194         Dialog::disconnect();
195 }
196
197
198 void GuiRef::resetDialog()
199 {
200         at_ref_ = false;
201         setGotoRef();
202 }
203
204
205 void GuiRef::closeEvent(QCloseEvent * e)
206 {
207         slotClose();
208         resetDialog();
209         e->accept();
210 }
211
212
213 void GuiRef::updateContents()
214 {
215         int orig_type = typeCO->currentIndex();
216
217         referenceED->setText(toqstr(params_["reference"]));
218
219         nameED->setText(toqstr(params_["name"]));
220         nameED->setReadOnly(!nameAllowed() && !isBufferReadonly());
221
222         // restore type settings for new insets
223         if (params_["reference"].empty())
224                 typeCO->setCurrentIndex(orig_type);
225         else
226                 typeCO->setCurrentIndex(InsetRef::getType(params_.getCmdName()));
227         typeCO->setEnabled(typeAllowed() && !isBufferReadonly());
228         if (!typeAllowed())
229                 typeCO->setCurrentIndex(0);
230
231         // insert buffer list
232         bufferCO->clear();
233         FileNameList const & buffers = theBufferList().fileNames();
234         for (FileNameList::const_iterator it = buffers.begin();
235              it != buffers.end(); ++it) {
236                 bufferCO->addItem(toqstr(makeDisplayPath(it->absFilename())));
237         }
238
239         int const thebuffer = theBufferList().bufferNum(buffer().fileName());
240         // restore the buffer combo setting for new insets
241         if (params_["reference"].empty() && restored_buffer_ != -1
242             && restored_buffer_ < bufferCO->count() && thebuffer == active_buffer_)
243                 bufferCO->setCurrentIndex(restored_buffer_);
244         else {
245                 int const num = theBufferList().bufferNum(buffer().fileName());
246                 bufferCO->setCurrentIndex(num);
247                 if (thebuffer != active_buffer_)
248                         restored_buffer_ = num;
249         }
250         active_buffer_ = thebuffer;
251
252         updateRefs();
253         bc().setValid(false);
254 }
255
256
257 void GuiRef::applyView()
258 {
259         last_reference_ = referenceED->text();
260
261         params_.setCmdName(InsetRef::getName(typeCO->currentIndex()));
262         params_["reference"] = qstring_to_ucs4(last_reference_);
263         params_["name"] = qstring_to_ucs4(nameED->text());
264
265         restored_buffer_ = bufferCO->currentIndex();
266 }
267
268
269 bool GuiRef::nameAllowed()
270 {
271         KernelDocType const doc_type = docType();
272         return doc_type != LATEX && doc_type != LITERATE;
273 }
274
275
276 bool GuiRef::typeAllowed()
277 {
278         return docType() != DOCBOOK;
279 }
280
281
282 void GuiRef::setGoBack()
283 {
284         gotoPB->setText(qt_("&Go Back"));
285         gotoPB->setToolTip("");
286         gotoPB->setToolTip(qt_("Jump back"));
287 }
288
289
290 void GuiRef::setGotoRef()
291 {
292         gotoPB->setText(qt_("&Go to Label"));
293         gotoPB->setToolTip("");
294         gotoPB->setToolTip(qt_("Jump to label"));
295 }
296
297
298 void GuiRef::gotoRef()
299 {
300         string ref = fromqstr(referenceED->text());
301
302         if (at_ref_) {
303                 // go back
304                 setGotoRef();
305                 gotoBookmark();
306         } else {
307                 // go to the ref
308                 setGoBack();
309                 gotoRef(ref);
310         }
311         at_ref_ = !at_ref_;
312 }
313
314 inline bool caseInsensitiveLessThan(QString const & s1, QString const & s2)
315 {
316         return s1.toLower() < s2.toLower();
317 }
318
319
320 void GuiRef::redoRefs()
321 {
322         // Prevent these widgets from emitting any signals whilst
323         // we modify their state.
324         refsLW->blockSignals(true);
325         referenceED->blockSignals(true);
326         refsLW->setUpdatesEnabled(false);
327
328         refsLW->clear();
329
330         // need this because Qt will send a highlight() here for
331         // the first item inserted
332         QString const oldSelection(referenceED->text());
333
334         QStringList refsStrings;
335         vector<docstring>::const_iterator iter;
336         for (iter = refs_.begin(); iter != refs_.end(); ++iter)
337                 refsStrings.append(toqstr(*iter));
338
339         if (sortCB->isEnabled() && sortCB->isChecked()) {
340                 if(caseSensitiveCB->isEnabled() && caseSensitiveCB->isChecked())
341                         qSort(refsStrings.begin(), refsStrings.end());
342                 else
343                         qSort(refsStrings.begin(), refsStrings.end(),
344                               caseInsensitiveLessThan /*defined above*/);
345         }
346
347         refsLW->addItems(refsStrings);
348
349         referenceED->setText(oldSelection);
350
351         // restore the last selection or, for new insets, highlight
352         // the previous selection
353         if (!oldSelection.isEmpty() || !last_reference_.isEmpty()) {
354                 bool const newInset = oldSelection.isEmpty();
355                 QString textToFind = newInset ? last_reference_ : oldSelection;
356                 last_reference_.clear();
357                 for (int i = 0; i != refsLW->count(); ++i) {
358                         QListWidgetItem * item = refsLW->item(i);
359                         if (textToFind == item->text()) {
360                                 refsLW->setCurrentItem(item);
361                                 refsLW->setItemSelected(item, !newInset);
362                                 //Make sure selected item is visible
363                                 refsLW->scrollToItem(item);
364                                 last_reference_ = textToFind;
365                                 break;
366                         }
367                 }
368         }
369         refsLW->setUpdatesEnabled(true);
370         refsLW->update();
371
372         // Re-activate the emission of signals by these widgets.
373         refsLW->blockSignals(false);
374         referenceED->blockSignals(false);
375 }
376
377
378 void GuiRef::updateRefs()
379 {
380         refs_.clear();
381         int const the_buffer = bufferCO->currentIndex();
382         if (the_buffer != -1) {
383                 FileName const & name = theBufferList().fileNames()[the_buffer];
384                 Buffer const * buf = theBufferList().getBuffer(name);
385                 buf->getLabelList(refs_);
386         }       
387         sortCB->setEnabled(!refs_.empty());
388         caseSensitiveCB->setEnabled(sortCB->isEnabled() && sortCB->isChecked());
389         refsLW->setEnabled(!refs_.empty());
390         // refsLW should only be the focus proxy when it is enabled
391         setFocusProxy(refs_.empty() ? 0 : refsLW);
392         gotoPB->setEnabled(!refs_.empty());
393         redoRefs();
394 }
395
396
397 bool GuiRef::isValid()
398 {
399         return !referenceED->text().isEmpty();
400 }
401
402
403 void GuiRef::gotoRef(string const & ref)
404 {
405         dispatch(FuncRequest(LFUN_BOOKMARK_SAVE, "0"));
406         dispatch(FuncRequest(LFUN_LABEL_GOTO, ref));
407 }
408
409
410 void GuiRef::gotoBookmark()
411 {
412         dispatch(FuncRequest(LFUN_BOOKMARK_GOTO, "0"));
413 }
414
415
416 bool GuiRef::initialiseParams(std::string const & data)
417 {
418         InsetCommand::string2params("ref", data, params_);
419         return true;
420 }
421
422
423 void GuiRef::dispatchParams()
424 {
425         std::string const lfun = InsetCommand::params2string("ref", params_);
426         dispatch(FuncRequest(getLfun(), lfun));
427 }
428
429
430
431 Dialog * createGuiRef(GuiView & lv) { return new GuiRef(lv); }
432
433
434 } // namespace frontend
435 } // namespace lyx
436
437 #include "moc_GuiRef.cpp"