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