2 * \file QCitationDialog.cpp
3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
6 * \author Kalle Dalheimer
8 * \author Jürgen Spitzmüller
9 * \author Abdelrazak Younes
11 * Full author contact details are available in file CREDITS.
16 #include "QCitationDialog.h"
18 #include "QCitation.h"
20 #include "frontends/controllers/frontend_helpers.h"
21 #include "frontends/controllers/ControlCitation.h"
23 #include "support/docstring.h"
32 #include <QCloseEvent>
44 QCitationDialog::QCitationDialog(Dialog & dialog, QCitation * form)
45 : Dialog::View(dialog, _("Citation")), form_(form)
49 setWindowTitle(toqstr("LyX: " + getTitle()));
51 selectedLV->setModel(form_->selected());
52 availableLV->setModel(form_->available());
54 connect(citationStyleCO, SIGNAL(activated(int)),
55 this, SLOT(changed()));
56 connect(fulllistCB, SIGNAL(clicked()),
57 this, SLOT(changed()));
58 connect(forceuppercaseCB, SIGNAL(clicked()),
59 this, SLOT(changed()));
60 connect(textBeforeED, SIGNAL(textChanged(const QString&)),
61 this, SLOT(changed()));
62 connect(textAfterED, SIGNAL(textChanged(const QString&)),
63 this, SLOT(changed()));
64 connect(clearPB, SIGNAL(clicked()),
65 findLE, SLOT(clear()));
66 connect(availableLV->selectionModel(),
67 SIGNAL(currentChanged(const QModelIndex &, const QModelIndex &)),
68 this, SLOT(availableChanged(const QModelIndex &, const QModelIndex &)));
69 connect(selectedLV->selectionModel(),
70 SIGNAL(currentChanged(const QModelIndex &, const QModelIndex &)),
71 this, SLOT(selectedChanged(const QModelIndex &, const QModelIndex &)));
72 connect(this, SIGNAL(rejected()), this, SLOT(cleanUp()));
73 availableLV->installEventFilter(this);
74 selectedLV->installEventFilter(this);
75 availableFocused_ = true;
79 QCitationDialog::~QCitationDialog()
84 bool QCitationDialog::eventFilter(QObject * obj, QEvent * event)
86 if (obj == availableLV) {
87 if (event->type() != QEvent::KeyPress)
88 return QObject::eventFilter(obj, event);
89 QKeyEvent * keyEvent = static_cast<QKeyEvent *>(event);
90 int const keyPressed = keyEvent->key();
91 Qt::KeyboardModifiers const keyModifiers = keyEvent->modifiers();
92 //Enter key without modifier will add current item.
93 //Ctrl-Enter will add it and close the dialog.
94 //This is designed to work both with the main enter key
95 //and the one on the numeric keypad.
96 if ((keyPressed == Qt::Key_Enter || keyPressed == Qt::Key_Return) &&
97 //We want one or both of Control and Keypad, and nothing else
98 //(KeypadModifier is what you get if you use the Enter key on the
101 (keyModifiers == Qt::ControlModifier) ||
102 (keyModifiers == Qt::KeypadModifier) ||
103 (keyModifiers == (Qt::ControlModifier | Qt::KeypadModifier))
106 if (addPB->isEnabled())
108 if (keyModifiers & Qt::ControlModifier)
113 } else if (obj == selectedLV) {
114 //Delete or backspace key will delete current item
115 //...with control modifier will clear the list
116 if (event->type() != QEvent::KeyPress)
117 return QObject::eventFilter(obj, event);
118 QKeyEvent * keyEvent = static_cast<QKeyEvent *>(event);
119 int const keyPressed = keyEvent->key();
120 Qt::KeyboardModifiers const keyModifiers = keyEvent->modifiers();
121 if (keyPressed == Qt::Key_Delete || keyPressed == Qt::Key_Backspace) {
122 if (keyModifiers == Qt::NoModifier && deletePB->isEnabled())
123 on_deletePB_clicked();
124 else if (keyModifiers == Qt::ControlModifier) {
125 form_->clearSelection();
128 //ignore it otherwise
129 return QObject::eventFilter(obj, event);
134 return QObject::eventFilter(obj, event);
138 void QCitationDialog::cleanUp()
140 form_->clearSelection();
141 form_->clearParams();
146 void QCitationDialog::closeEvent(QCloseEvent * e)
148 form_->clearSelection();
149 form_->clearParams();
154 void QCitationDialog::apply()
156 int const choice = std::max(0, citationStyleCO->currentIndex());
158 bool const full = fulllistCB->isChecked();
159 bool const force = forceuppercaseCB->isChecked();
161 QString const before = textBeforeED->text();
162 QString const after = textAfterED->text();
164 form_->apply(choice, full, force, before, after);
168 void QCitationDialog::hide()
170 form_->clearParams();
175 void QCitationDialog::show()
178 availableLV->setFocus();
185 bool QCitationDialog::isVisible() const
187 return QDialog::isVisible();
191 void QCitationDialog::on_okPB_clicked()
194 form_->clearSelection();
199 void QCitationDialog::on_cancelPB_clicked()
201 form_->clearSelection();
206 void QCitationDialog::on_applyPB_clicked()
212 void QCitationDialog::on_restorePB_clicked()
219 void QCitationDialog::update()
227 //The main point of separating this out is that the fill*() methods
228 //called in update() do not need to be called for INTERNAL updates,
229 //such as when addPB is pressed, as the list of fields, entries, etc,
230 //will not have changed. At the moment, however, the division between
231 //fillStyles() and updateStyles() doesn't lend itself to dividing the
232 //two methods, though they should be divisible.
233 void QCitationDialog::updateDialog()
235 if (availableFocused_ ||
236 selectedLV->selectionModel()->selectedIndexes().isEmpty()) {
237 if (availableLV->selectionModel()->selectedIndexes().isEmpty()
238 && availableLV->model()->rowCount() > 0)
239 availableLV->setCurrentIndex(availableLV->model()->index(0,0));
240 updateInfo(availableLV);
242 updateInfo(selectedLV);
246 textBeforeED->setText(form_->textBefore());
247 textAfterED->setText(form_->textAfter());
253 void QCitationDialog::updateStyle()
255 biblio::CiteEngine const engine = form_->getEngine();
256 bool const natbib_engine =
257 engine == biblio::ENGINE_NATBIB_AUTHORYEAR ||
258 engine == biblio::ENGINE_NATBIB_NUMERICAL;
259 bool const basic_engine = engine == biblio::ENGINE_BASIC;
261 bool const haveSelection =
262 selectedLV->model()->rowCount() > 0;
263 fulllistCB->setEnabled(natbib_engine && haveSelection);
264 forceuppercaseCB->setEnabled(natbib_engine && haveSelection);
265 textBeforeED->setEnabled(!basic_engine && haveSelection);
266 textBeforeLA->setEnabled(!basic_engine && haveSelection);
267 textAfterED->setEnabled(haveSelection);
268 textAfterLA->setEnabled(haveSelection);
269 citationStyleCO->setEnabled(!basic_engine && haveSelection);
270 citationStyleLA->setEnabled(!basic_engine && haveSelection);
272 string const & command = form_->params().getCmdName();
274 // Find the style of the citekeys
275 vector<biblio::CiteStyle> const & styles =
276 ControlCitation::getCiteStyles();
277 biblio::CitationStyle const cs(command);
279 vector<biblio::CiteStyle>::const_iterator cit =
280 std::find(styles.begin(), styles.end(), cs.style);
282 // restore the latest natbib style
283 if (style_ >= 0 && style_ < citationStyleCO->count())
284 citationStyleCO->setCurrentIndex(style_);
286 citationStyleCO->setCurrentIndex(0);
288 if (cit != styles.end()) {
289 int const i = int(cit - styles.begin());
290 citationStyleCO->setCurrentIndex(i);
291 fulllistCB->setChecked(cs.full);
292 forceuppercaseCB->setChecked(cs.forceUCase);
294 fulllistCB->setChecked(false);
295 forceuppercaseCB->setChecked(false);
300 //This one needs to be called whenever citationStyleCO needs
301 //to be updated---and this would be on anything that changes the
302 //selection in selectedLV, or on a general update.
303 void QCitationDialog::fillStyles()
305 int const oldIndex = citationStyleCO->currentIndex();
307 citationStyleCO->clear();
309 QStringList selected_keys = form_->selected()->stringList();
310 if (selected_keys.empty()) {
311 citationStyleCO->setEnabled(false);
312 citationStyleLA->setEnabled(false);
316 int curr = selectedLV->model()->rowCount() - 1;
320 if (!selectedLV->selectionModel()->selectedIndexes().empty())
321 curr = selectedLV->selectionModel()->selectedIndexes()[0].row();
323 QStringList sty = form_->citationStyles(curr);
325 bool const basic_engine =
326 (form_->getEngine() == biblio::ENGINE_BASIC);
328 citationStyleCO->setEnabled(!sty.isEmpty() && !basic_engine);
329 citationStyleLA->setEnabled(!sty.isEmpty() && !basic_engine);
331 if (sty.isEmpty() || basic_engine)
334 citationStyleCO->insertItems(0, sty);
336 if (oldIndex != -1 && oldIndex < citationStyleCO->count())
337 citationStyleCO->setCurrentIndex(oldIndex);
341 void QCitationDialog::fillFields()
343 fieldsCO->blockSignals(true);
344 int const oldIndex = fieldsCO->currentIndex();
346 QStringList const & fields = form_->getFieldsAsQStringList();
347 fieldsCO->insertItem(0, qt_("All Fields"));
348 fieldsCO->insertItem(1, qt_("Keys"));
349 fieldsCO->insertItems(2, fields);
350 if (oldIndex != -1 && oldIndex < fieldsCO->count())
351 fieldsCO->setCurrentIndex(oldIndex);
352 fieldsCO->blockSignals(false);
356 void QCitationDialog::fillEntries()
358 entriesCO->blockSignals(true);
359 int const oldIndex = entriesCO->currentIndex();
361 QStringList const & entries = form_->getEntriesAsQStringList();
362 entriesCO->insertItem(0, qt_("All Entry Types"));
363 entriesCO->insertItems(1, entries);
364 if (oldIndex != -1 && oldIndex < entriesCO->count())
365 entriesCO->setCurrentIndex(oldIndex);
366 entriesCO->blockSignals(false);
370 bool QCitationDialog::isSelected(const QModelIndex & idx)
372 QString const str = idx.data().toString();
373 return form_->selected()->stringList().contains(str);
377 void QCitationDialog::setButtons()
379 int const arows = availableLV->model()->rowCount();
380 QModelIndexList const availSels =
381 availableLV->selectionModel()->selectedIndexes();
382 addPB->setEnabled(arows > 0 &&
383 !availSels.isEmpty() &&
384 !isSelected(availSels.first()));
386 int const srows = selectedLV->model()->rowCount();
387 QModelIndexList const selSels =
388 selectedLV->selectionModel()->selectedIndexes();
389 int const sel_nr = selSels.empty() ? -1 : selSels.first().row();
390 deletePB->setEnabled(sel_nr >= 0);
391 upPB->setEnabled(sel_nr > 0);
392 downPB->setEnabled(sel_nr >= 0 && sel_nr < srows - 1);
396 void QCitationDialog::updateInfo(QListView const * const qlv)
398 QModelIndex idx = qlv->currentIndex();
400 QString const keytxt = form_->getKeyInfo(idx.data().toString());
401 infoML->document()->setPlainText(keytxt);
403 infoML->document()->clear();
407 void QCitationDialog::on_selectedLV_clicked(const QModelIndex &)
409 availableFocused_ = false;
414 void QCitationDialog::selectedChanged(const QModelIndex & idx, const QModelIndex &)
422 void QCitationDialog::on_availableLV_clicked(const QModelIndex &)
424 availableFocused_ = true;
429 void QCitationDialog::availableChanged(const QModelIndex & idx, const QModelIndex &)
433 availableFocused_ = true;
438 void QCitationDialog::on_availableLV_doubleClicked(const QModelIndex & idx)
442 availableFocused_ = true;
448 //helper function for next two
449 QModelIndex getSelectedIndex(QListView * lv) {
450 //Encourage compiler to use NRVO
451 QModelIndex retval = QModelIndex();
452 QModelIndexList selIdx =
453 lv->selectionModel()->selectedIndexes();
455 retval = selIdx.first();
458 }//anonymous namespace
461 void QCitationDialog::on_addPB_clicked()
463 QModelIndex const idxToAdd = getSelectedIndex(availableLV);
464 if (!idxToAdd.isValid())
466 QModelIndex idx = selectedLV->currentIndex();
467 form_->addKey(idxToAdd);
469 selectedLV->setCurrentIndex(idx);
470 availableFocused_ = true;
475 void QCitationDialog::on_deletePB_clicked()
477 QModelIndex idx = getSelectedIndex(selectedLV);
480 int nrows = selectedLV->model()->rowCount();
482 form_->deleteKey(idx);
484 if (idx.row() == nrows - 1)
485 idx = idx.sibling(idx.row() - 1, idx.column());
488 selectedLV->setCurrentIndex(idx);
489 availableFocused_ = true;
494 void QCitationDialog::on_upPB_clicked()
496 QModelIndex idx = selectedLV->currentIndex();
498 selectedLV->setCurrentIndex(idx.sibling(idx.row() - 1, idx.column()));
499 availableLV->selectionModel()->reset();
500 availableFocused_ = false;
505 void QCitationDialog::on_downPB_clicked()
507 QModelIndex idx = selectedLV->currentIndex();
509 selectedLV->setCurrentIndex(idx.sibling(idx.row() + 1, idx.column()));
510 availableLV->selectionModel()->reset();
511 availableFocused_ = false;
516 void QCitationDialog::findText(QString const & text, bool reset)
518 //"All Fields" and "Keys" are the first two
519 int index = fieldsCO->currentIndex() - 2;
520 vector<docstring> const & fields = form_->availableFields();
523 if (index <= -1 || index >= int(fields.size()))
524 //either "All Fields" or "Keys" or an invalid value
525 field = from_ascii("");
527 field = fields[index];
530 bool const onlyKeys = index == -1;
532 //"All Entry Types" is first.
533 index = entriesCO->currentIndex() - 1;
534 vector<docstring> const & entries = form_->availableEntries();
536 if (index < 0 || index >= int(entries.size()))
537 entryType = from_ascii("");
539 entryType = entries[index];
541 bool const case_sentitive = caseCB->checkState();
542 bool const reg_exp = regexCB->checkState();
543 form_->findKey(text, onlyKeys, field, entryType,
544 case_sentitive, reg_exp, reset);
546 //It'd be nice to save and restore the current selection in
547 //availableLV. Currently, we get an automatic reset, since the
554 void QCitationDialog::on_fieldsCO_currentIndexChanged(int /*index*/)
556 findText(findLE->text(), true);
560 void QCitationDialog::on_entriesCO_currentIndexChanged(int /*index*/)
562 findText(findLE->text(), true);
566 void QCitationDialog::on_findLE_textChanged(const QString & text)
568 clearPB->setDisabled(text.isEmpty());
575 void QCitationDialog::on_caseCB_stateChanged(int)
577 findText(findLE->text());
581 void QCitationDialog::on_regexCB_stateChanged(int)
583 findText(findLE->text());
587 void QCitationDialog::changed()
594 } // namespace frontend
597 #include "QCitationDialog_moc.cpp"