]> git.lyx.org Git - lyx.git/blob - src/frontends/qt4/QCitationDialog.cpp
fix building with automake; break scons, cmake and qmake
[lyx.git] / src / frontends / qt4 / QCitationDialog.cpp
1 /**
2  * \file QCitationDialog.cpp
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Kalle Dalheimer
7  * \author John Levon
8  * \author Jürgen Spitzmüller
9  * \author Abdelrazak Younes
10  *
11  * Full author contact details are available in file CREDITS.
12  */
13
14 #include <config.h>
15
16 #include "QCitationDialog.h"
17
18 #include "QCitation.h"
19
20 #include "frontends/controllers/frontend_helpers.h"
21 #include "frontends/controllers/ControlCitation.h"
22
23 #include "debug.h"
24 #include "gettext.h"
25
26 #include <algorithm>
27 #include <vector>
28 #include <string>
29
30 #include <QCloseEvent>
31 #include <QKeyEvent>
32
33 using std::vector;
34 using std::string;
35
36 namespace lyx {
37 namespace frontend {
38
39
40 QCitationDialog::QCitationDialog(Dialog & dialog, QCitation * form)
41         : Dialog::View(dialog, _("Citation")), form_(form)
42 {
43         setupUi(this);
44
45         setWindowTitle(toqstr("LyX: " + getTitle()));
46
47         selectedLV->setModel(form_->selected());
48         availableLV->setModel(form_->available());
49
50         connect(citationStyleCO, SIGNAL(activated(int)),
51                 this, SLOT(changed()));
52         connect(fulllistCB, SIGNAL(clicked()),
53                 this, SLOT(changed()));
54         connect(forceuppercaseCB, SIGNAL(clicked()),
55                 this, SLOT(changed()));
56         connect(textBeforeED, SIGNAL(textChanged(const QString&)),
57                 this, SLOT(changed()));
58         connect(textAfterED, SIGNAL(textChanged(const QString&)),
59                 this, SLOT(changed()));
60         connect(clearPB, SIGNAL(clicked()),
61                 findLE, SLOT(clear()));
62         connect(availableLV->selectionModel(),
63                 SIGNAL(currentChanged(const QModelIndex &, const QModelIndex &)),
64                 this, SLOT(availableChanged(const QModelIndex &, const QModelIndex &)));
65         connect(selectedLV->selectionModel(),
66                 SIGNAL(currentChanged(const QModelIndex &, const QModelIndex &)),
67                 this, SLOT(selectedChanged(const QModelIndex &, const QModelIndex &)));
68         connect(this, SIGNAL(rejected()), this, SLOT(cleanUp()));
69         availableLV->installEventFilter(this);
70         selectedLV->installEventFilter(this);
71 }
72
73
74 QCitationDialog::~QCitationDialog()
75 {
76 }
77
78
79 bool QCitationDialog::eventFilter(QObject * obj, QEvent * event) 
80 {
81         if (obj == availableLV) {
82                 if (event->type() != QEvent::KeyPress)
83                         return QObject::eventFilter(obj, event);
84                 QKeyEvent * keyEvent = static_cast<QKeyEvent *>(event);
85                 int const keyPressed = keyEvent->key();
86                 Qt::KeyboardModifiers const keyModifiers = keyEvent->modifiers();
87                 //Enter key without modifier will add current item.
88                 //Ctrl-Enter will add it and close the dialog.
89                 //This is designed to work both with the main enter key
90                 //and the one on the numeric keypad.
91                 if ((keyPressed == Qt::Key_Enter || keyPressed == Qt::Key_Return) &&
92                                 //We want one or both of Control and Keypad, and nothing else
93                                 //(KeypadModifier is what you get if you use the Enter key on the
94                                 //numeric keypad.)
95                                 (!keyModifiers || 
96                                  (keyModifiers == Qt::ControlModifier) ||
97                                  (keyModifiers == Qt::KeypadModifier)  ||
98                                  (keyModifiers == (Qt::ControlModifier | Qt::KeypadModifier))
99                                 )
100                         ) {
101                                 if (addPB->isEnabled())
102                                         on_addPB_clicked();
103                                 if (keyModifiers & Qt::ControlModifier)
104                                         on_okPB_clicked();
105                                 event->accept();
106                                 return true;
107                 } 
108         } else if (obj == selectedLV) {
109                 //Delete or backspace key will delete current item
110                 //...with control modifier will clear the list
111                 if (event->type() != QEvent::KeyPress)
112                         return QObject::eventFilter(obj, event);
113                 QKeyEvent * keyEvent = static_cast<QKeyEvent *>(event);
114                 int const keyPressed = keyEvent->key();
115                 Qt::KeyboardModifiers const keyModifiers = keyEvent->modifiers();
116                 if (keyPressed == Qt::Key_Delete || keyPressed == Qt::Key_Backspace) {
117                         if (keyModifiers == Qt::NoModifier && deletePB->isEnabled())
118                                 on_deletePB_clicked();
119                         else if (keyModifiers == Qt::ControlModifier) {
120                                 form_->clearSelection();
121                                 update();
122                         } else
123                                 //ignore it otherwise
124                                 return QObject::eventFilter(obj, event);
125                         event->accept();
126                         return true;
127                 }
128         }
129         return QObject::eventFilter(obj, event);
130 }
131
132
133 void QCitationDialog::cleanUp() 
134 {
135         form_->clearSelection();
136         form_->clearParams();
137         close();
138 }
139
140
141 void QCitationDialog::closeEvent(QCloseEvent * e)
142 {
143         form_->clearSelection();
144         form_->clearParams();
145         e->accept();
146 }
147
148
149 void QCitationDialog::apply()
150 {
151         int  const choice = std::max(0, citationStyleCO->currentIndex());
152         style_ = choice;
153         bool const full  = fulllistCB->isChecked();
154         bool const force = forceuppercaseCB->isChecked();
155
156         QString const before = textBeforeED->text();
157         QString const after = textAfterED->text();
158
159         form_->apply(choice, full, force, before, after);
160 }
161
162
163 void QCitationDialog::hide()
164 {
165         form_->clearParams();
166         accept();
167 }
168
169
170 void QCitationDialog::show()
171 {
172         findLE->clear();
173         availableLV->setFocus();
174         QDialog::show();
175         raise();
176         activateWindow();
177 }
178
179
180 bool QCitationDialog::isVisible() const
181 {
182         return QDialog::isVisible();
183 }
184
185
186 void QCitationDialog::on_okPB_clicked()
187 {
188         apply();
189         form_->clearSelection();
190         hide();
191 }
192
193
194 void QCitationDialog::on_cancelPB_clicked()
195 {
196         form_->clearSelection();
197         hide();
198 }
199
200
201 void QCitationDialog::on_applyPB_clicked()
202 {
203         apply();
204 }
205
206
207 void QCitationDialog::on_restorePB_clicked()
208 {
209         form_->init();
210         update();
211 }
212
213
214 void QCitationDialog::update()
215 {
216         if (selectedLV->selectionModel()->selectedIndexes().isEmpty()) {
217                 if (availableLV->selectionModel()->selectedIndexes().isEmpty()
218                         && availableLV->model()->rowCount() > 0)
219                                 availableLV->setCurrentIndex(availableLV->model()->index(0,0));
220                 updateInfo(availableLV->currentIndex());
221         } else
222                 updateInfo(selectedLV->currentIndex());
223
224         setButtons();
225
226         textBeforeED->setText(form_->textBefore());
227         textAfterED->setText(form_->textAfter());
228
229         fillStyles();
230         updateStyle();
231 }
232
233
234 void QCitationDialog::updateStyle()
235 {
236         biblio::CiteEngine const engine = form_->getEngine();
237         bool const natbib_engine =
238                 engine == biblio::ENGINE_NATBIB_AUTHORYEAR ||
239                 engine == biblio::ENGINE_NATBIB_NUMERICAL;
240         bool const basic_engine = engine == biblio::ENGINE_BASIC;
241
242         fulllistCB->setEnabled(natbib_engine);
243         forceuppercaseCB->setEnabled(natbib_engine);
244         textBeforeED->setEnabled(!basic_engine);
245         textBeforeLA->setEnabled(!basic_engine);
246
247         string const & command = form_->params().getCmdName();
248
249         // Find the style of the citekeys
250         vector<biblio::CiteStyle> const & styles =
251                 ControlCitation::getCiteStyles();
252         biblio::CitationStyle const cs(command);
253
254         vector<biblio::CiteStyle>::const_iterator cit =
255                 std::find(styles.begin(), styles.end(), cs.style);
256
257         // restore the latest natbib style
258         if (style_ >= 0 && style_ < citationStyleCO->count())
259                 citationStyleCO->setCurrentIndex(style_);
260         else
261                 citationStyleCO->setCurrentIndex(0);
262
263         fulllistCB->setChecked(false);
264         forceuppercaseCB->setChecked(false);
265
266         if (cit != styles.end()) {
267                 int const i = int(cit - styles.begin());
268                 citationStyleCO->setCurrentIndex(i);
269                 fulllistCB->setChecked(cs.full);
270                 forceuppercaseCB->setChecked(cs.forceUCase);
271         }
272 }
273
274
275 void QCitationDialog::fillStyles()
276 {
277         int const orig = citationStyleCO->currentIndex();
278
279         citationStyleCO->clear();
280
281         QStringList selected_keys = form_->selected()->stringList();
282         if (selected_keys.empty()) {
283                 citationStyleCO->setEnabled(false);
284                 citationStyleLA->setEnabled(false);
285                 return;
286         }
287
288         int curr = selectedLV->model()->rowCount() - 1;
289         if (curr < 0)
290                 return;
291
292         if (!selectedLV->selectionModel()->selectedIndexes().empty())
293                 curr = selectedLV->selectionModel()->selectedIndexes()[0].row();
294
295         QStringList sty = form_->citationStyles(curr);
296
297         bool const basic_engine =
298                 (form_->getEngine() == biblio::ENGINE_BASIC);
299
300         citationStyleCO->setEnabled(!sty.isEmpty() && !basic_engine);
301         citationStyleLA->setEnabled(!sty.isEmpty() && !basic_engine);
302
303         if (sty.isEmpty() || basic_engine)
304                 return;
305
306         citationStyleCO->insertItems(0, sty);
307
308         if (orig != -1 && orig < citationStyleCO->count())
309                 citationStyleCO->setCurrentIndex(orig);
310 }
311
312
313 bool QCitationDialog::isSelected(const QModelIndex & idx)
314 {
315         QString const str = idx.data().toString();
316         return form_->selected()->stringList().contains(str);
317 }
318
319
320 void QCitationDialog::setButtons()
321 {
322         int const arows = availableLV->model()->rowCount();
323         addPB->setEnabled(arows > 0 &&
324                 availableLV->currentIndex().isValid() &&
325                 !isSelected(availableLV->currentIndex()));
326
327         int const srows = selectedLV->model()->rowCount();
328         int const sel_nr = selectedLV->currentIndex().row();
329         deletePB->setEnabled(sel_nr >= 0);
330         upPB->setEnabled(sel_nr > 0);
331         downPB->setEnabled(sel_nr >= 0 && sel_nr < srows - 1);
332         applyPB->setEnabled(srows > 0);
333         okPB->setEnabled(srows > 0);
334 }
335
336
337 void QCitationDialog::updateInfo(const QModelIndex & idx)
338 {
339         if (idx.isValid()) {
340                 QString const keytxt = form_->getKeyInfo(idx.data().toString());
341                 infoML->document()->setPlainText(keytxt);
342         } else
343                 infoML->document()->clear();
344 }
345
346
347 void QCitationDialog::on_selectedLV_clicked(const QModelIndex &)
348 {
349         availableLV->selectionModel()->reset();
350         update();
351 }
352
353
354 void QCitationDialog::selectedChanged(const QModelIndex & idx, const QModelIndex &)
355 {
356         if (!idx.isValid())
357                 return;
358
359         availableLV->selectionModel()->reset();
360         update();
361 }
362
363
364 void QCitationDialog::on_availableLV_clicked(const QModelIndex &)
365 {
366         selectedLV->selectionModel()->reset();
367         update();
368 }
369
370
371 void QCitationDialog::availableChanged(const QModelIndex & idx, const QModelIndex &)
372 {
373         if (!idx.isValid())
374                 return;
375
376         selectedLV->selectionModel()->reset();
377         update();
378 }
379
380
381 void QCitationDialog::on_availableLV_doubleClicked(const QModelIndex & idx)
382 {
383         if (isSelected(idx))
384                 return;
385
386         selectedLV->selectionModel()->reset();
387         on_addPB_clicked();
388 }
389
390
391 void QCitationDialog::on_availableLV_entered(const QModelIndex &)
392 {
393 }
394
395
396 namespace {
397 //helper function for next two
398 QModelIndex getSelectedIndex(QListView * lv) {
399         //Encourage compiler to use NRVO
400         QModelIndex retval = QModelIndex();
401         QModelIndexList selIdx = 
402                 lv->selectionModel()->selectedIndexes();
403         if (!selIdx.empty())
404                 retval = selIdx.first();
405         return retval;
406 }
407 }//anonymous namespace
408
409
410 void QCitationDialog::on_addPB_clicked()
411 {
412         QModelIndex const idxToAdd = getSelectedIndex(availableLV);
413         if (!idxToAdd.isValid())
414                 return;
415         QModelIndex idx = selectedLV->currentIndex();
416         form_->addKey(idxToAdd);
417         if (idx.isValid())
418                 selectedLV->setCurrentIndex(idx);
419         selectedLV->selectionModel()->reset();
420         update();
421 }
422
423
424 void QCitationDialog::on_deletePB_clicked()
425 {
426         QModelIndex idx = getSelectedIndex(selectedLV);
427         if (!idx.isValid())
428                 return;
429         int nrows = selectedLV->model()->rowCount();
430
431         form_->deleteKey(idx);
432
433         if (idx.row() == nrows - 1)
434                 idx = idx.sibling(idx.row() - 1, idx.column());
435
436         if (nrows>1)
437                 selectedLV->setCurrentIndex(idx);
438
439         availableLV->selectionModel()->reset();
440         update();
441 }
442
443
444 void QCitationDialog::on_upPB_clicked()
445 {
446         QModelIndex idx = selectedLV->currentIndex();
447         form_->upKey(idx);
448         selectedLV->setCurrentIndex(idx.sibling(idx.row() - 1, idx.column()));
449         availableLV->selectionModel()->reset();
450         update();
451 }
452
453
454 void QCitationDialog::on_downPB_clicked()
455 {
456         QModelIndex idx = selectedLV->currentIndex();
457         form_->downKey(idx);
458         selectedLV->setCurrentIndex(idx.sibling(idx.row() + 1, idx.column()));
459         availableLV->selectionModel()->reset();
460         update();
461 }
462
463
464 void QCitationDialog::findText(QString const & text)
465 {
466         bool const case_sentitive = caseCB->checkState();
467         bool const reg_exp = regexCB->checkState();
468         form_->findKey(text, false, case_sentitive, reg_exp);
469         selectedLV->selectionModel()->reset();
470         update();
471 }
472
473
474 void QCitationDialog::on_findLE_textChanged(const QString & text)
475 {
476         clearPB->setDisabled(text.isEmpty());
477         if (text.isEmpty())
478                 findLE->setFocus();
479         findText(text);
480 }
481
482
483 void QCitationDialog::on_caseCB_stateChanged(int)
484 {
485         findText(findLE->text());
486 }
487
488
489 void QCitationDialog::on_regexCB_stateChanged(int)
490 {
491         findText(findLE->text());
492 }
493
494
495 void QCitationDialog::changed()
496 {
497         fillStyles();
498         setButtons();
499 }
500
501
502 } // namespace frontend
503 } // namespace lyx
504
505 #include "QCitationDialog_moc.cpp"