3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
6 * \author Bernhard Reiter
8 * Full author contact details are available in file CREDITS.
13 // Too hard to make concept checks work with this file
14 #ifdef _GLIBCXX_CONCEPT_CHECKS
15 #undef _GLIBCXX_CONCEPT_CHECKS
17 #ifdef _GLIBCPP_CONCEPT_CHECKS
18 #undef _GLIBCPP_CONCEPT_CHECKS
21 #include "GCitation.h"
22 #include "ControlCitation.h"
25 #include "bufferparams.h"
27 #include "support/lstrings.h"
29 #include <libglademm.h>
37 class bibModelColumns : public Gtk::TreeModel::ColumnRecord
41 bibModelColumns() { add(name); add(cite); add(bib_order); add(info); }
43 Gtk::TreeModelColumn<Glib::ustring> name;
44 Gtk::TreeModelColumn<bool> cite;
45 Gtk::TreeModelColumn<int> bib_order;
46 Gtk::TreeModelColumn<Glib::ustring> info;
49 bibModelColumns bibColumns;
51 class styleModelColumns : public Gtk::TreeModel::ColumnRecord
55 styleModelColumns() { add(name); }
57 Gtk::TreeModelColumn<Glib::ustring> name;
60 bool GCitation::bib_visible(const Gtk::TreeModel::const_iterator& iter)
63 return !((*iter)[bibColumns.cite]);
67 styleModelColumns styleColumns;
71 GCitation::GCitation(Dialog & parent)
72 : GViewCB<ControlCitation, GViewGladeB>(parent, lyx::to_utf8(_("Citation")), false)
76 void GCitation::doBuild()
78 string const gladeName = findGladeFile("citation");
79 xml_ = Gnome::Glade::Xml::create(gladeName);
81 xml_->get_widget("Restore", restorebutton_);
82 setRestore(restorebutton_);
83 xml_->get_widget("Cancel", cancelbutton_);
84 setCancel(cancelbutton_);
85 xml_->get_widget("Apply", applybutton_);
86 setApply(applybutton_);
87 xml_->get_widget("OK", okbutton_);
90 xml_->get_widget("Remove", removebutton_);
91 xml_->get_widget("Add", addbutton_);
92 xml_->get_widget("Back", backbutton_);
93 xml_->get_widget("Forward", forwardbutton_);
94 xml_->get_widget("Up", upbutton_);
95 xml_->get_widget("Down", downbutton_);
97 xml_->get_widget("CiteKeys", citekeysview_);
98 xml_->get_widget("BibKeys", bibkeysview_);
99 xml_->get_widget("Info", infoview_);
100 xml_->get_widget("CaseSensitive", casecheck_);
102 xml_->get_widget("SearchString", findentry_);
103 xml_->get_widget("CaseSensitive", casecheck_);
104 xml_->get_widget("RegularExpression", regexpcheck_);
106 xml_->get_widget("StyleLabel", stylelabel_);
107 xml_->get_widget("Style", stylecombo_);
108 xml_->get_widget("TextBeforeLabel", beforelabel_);
109 xml_->get_widget("TextBefore", beforeentry_);
110 xml_->get_widget("TextAfter", afterentry_);
111 xml_->get_widget("FullAuthorList", authorcheck_);
112 xml_->get_widget("ForceUpperCase", uppercasecheck_);
114 info_ = Gtk::TextBuffer::create();
115 infoview_->set_buffer(info_);
117 allListStore_ = Gtk::ListStore::create(bibColumns);
119 Gtk::TreeModel::Path rootpath; //required for gtkmm < 2.6
122 citekeysview_->append_column(lyx::to_utf8(_("CiteKeys")), bibColumns.name);
123 citeFilter_ = Gtk::TreeModelFilter::create(allListStore_, rootpath);
124 citeFilter_->set_visible_column(bibColumns.cite);
125 citekeysview_->set_model(citeFilter_);
126 citeselection_ = citekeysview_->get_selection();
129 bibkeysview_->append_column(lyx::to_utf8(_("BibKeys")), bibColumns.name);
130 bibSort_ = Gtk::TreeModelSort::create(allListStore_);
131 bibSort_->set_sort_column(bibColumns.bib_order, Gtk::SORT_ASCENDING );
132 bibFilter_ = Gtk::TreeModelFilter::create(bibSort_, rootpath);
133 bibFilter_->set_visible_func(&GCitation::bib_visible);
134 bibkeysview_->set_model(bibFilter_);
135 bibselection_ = bibkeysview_->get_selection();
137 styleStore_ = Gtk::ListStore::create(styleColumns);
138 stylecombo_->set_model(styleStore_);
140 upbutton_->signal_clicked().connect(
141 sigc::mem_fun(*this, &GCitation::up));
142 downbutton_->signal_clicked().connect(
143 sigc::mem_fun(*this, &GCitation::down));
144 addbutton_->signal_clicked().connect(
145 sigc::mem_fun(*this, &GCitation::add));
146 removebutton_->signal_clicked().connect(
147 sigc::mem_fun(*this, &GCitation::remove));
148 backbutton_->signal_clicked().connect(
149 sigc::mem_fun(*this, &GCitation::previous));
150 forwardbutton_->signal_clicked().connect(
151 sigc::mem_fun(*this, &GCitation::next));
153 findentry_->signal_changed().connect(
154 sigc::mem_fun(*this, &GCitation::set_search_buttons));
156 bibkeysview_->signal_row_activated().connect(
157 sigc::mem_fun(*this, &GCitation::bibkeysview_activated));
158 bibselection_->signal_changed().connect(
159 sigc::mem_fun(*this, &GCitation::bib_selected));
161 citeselection_->signal_changed().connect(
162 sigc::mem_fun(*this, &GCitation::cite_selected));
164 beforeentry_->signal_changed().connect(
165 sigc::mem_fun(*this, &GCitation::enable_apply));
166 afterentry_->signal_changed().connect(
167 sigc::mem_fun(*this, &GCitation::enable_apply));
168 stylecombo_->signal_changed().connect(
169 sigc::mem_fun(*this, &GCitation::enable_apply));
170 authorcheck_->signal_toggled().connect(
171 sigc::mem_fun(*this, &GCitation::enable_apply));
172 uppercasecheck_->signal_toggled().connect(
173 sigc::mem_fun(*this, &GCitation::enable_apply));
178 void GCitation::enable_apply() {
179 // if we passed !applylock_ directly as an argument, the restore button
180 // would be activated
181 if (!applylock_ && !(citeFilter_->children()).empty())
186 void GCitation::fill_styles()
188 if ((citeFilter_->children()).empty()) {
189 stylecombo_->set_sensitive(false);
190 stylelabel_->set_sensitive(false);
194 int orig = stylecombo_->get_active_row_number();
196 Gtk::TreeModel::iterator iter = citeselection_->get_selected();
198 iter = (citeFilter_->children()).begin();
199 string key = Glib::locale_from_utf8((*iter)[bibColumns.name]);
201 std::vector<string> const & sty = controller().getCiteStrings(key);
203 biblio::CiteEngine const engine = controller().getEngine();
204 bool const basic_engine = engine == biblio::ENGINE_BASIC;
206 stylecombo_->set_sensitive(!sty.empty() && !basic_engine);
207 stylelabel_->set_sensitive(!sty.empty() && !basic_engine);
209 vector<string>::const_iterator it = sty.begin();
210 vector<string>::const_iterator const end = sty.end();
212 styleStore_->clear();
213 for (; it != end; ++it) {
214 Gtk::TreeModel::iterator iter2 = styleStore_->append();
215 (*iter2)[styleColumns.name] = Glib::locale_to_utf8(*it);
219 stylecombo_->set_active(orig);
223 void GCitation::update_style()
225 biblio::CiteEngine const engine = controller().getEngine();
226 bool const natbib_engine =
227 engine == biblio::ENGINE_NATBIB_AUTHORYEAR ||
228 engine == biblio::ENGINE_NATBIB_NUMERICAL;
229 bool const basic_engine = engine == biblio::ENGINE_BASIC;
231 authorcheck_->set_sensitive(natbib_engine);
232 uppercasecheck_->set_sensitive(natbib_engine);
233 beforeentry_->set_sensitive(!basic_engine);
234 beforelabel_->set_sensitive(!basic_engine);
236 string const & command = controller().params().getCmdName();
238 // Find the style of the citekeys
239 vector<biblio::CiteStyle> const & styles =
240 ControlCitation::getCiteStyles();
241 biblio::CitationStyle const cs(command);
243 vector<biblio::CiteStyle>::const_iterator cit =
244 std::find(styles.begin(), styles.end(), cs.style);
246 //restore the latest natbib style
247 if (style_ >= 0 && Gtk::TreeModel::Children::size_type(style_) <
248 (styleStore_->children()).size())
249 stylecombo_->set_active(style_);
251 stylecombo_->unset_active();
253 authorcheck_->set_active(false);
254 uppercasecheck_->set_active(false);
256 if (cit != styles.end()) {
257 stylecombo_->set_active(cit - styles.begin());
258 authorcheck_->set_active(cs.full);
259 uppercasecheck_->set_active(cs.forceUCase);
264 void GCitation::update_contents()
266 // Make a list of all available bibliography keys
267 biblio::InfoMap const & theMap = controller().bibkeysInfo();
268 std::vector<std::string> bibkeys = biblio::getKeys(theMap);
269 std::vector<std::string> citekeys = support::getVectorFromString(
270 controller().params().getContents());
273 allListStore_->clear();
275 for (std::vector<std::string>::const_iterator cit = bibkeys.begin();
276 cit != bibkeys.end(); ++cit) {
278 Gtk::TreeModel::iterator iter = allListStore_->append();
279 // ENCODING, FIXME: assuming ISO-8859 only for key name and info fields
280 // This is a hack to avoid a crash when populating the dialog from bibtex
281 // files containing non-ASCII characters.
282 (*iter)[bibColumns.name] = Glib::convert(*cit, "UTF-8", "ISO-8859-1");
283 (*iter)[bibColumns.cite] = false; //reset state
284 (*iter)[bibColumns.bib_order] = ++bib_order;
285 (*iter)[bibColumns.info] = Glib::convert(biblio::getInfo(theMap,*cit), "UTF-8", "ISO-8859-1");
288 // Now mark cite keys by setting their bibColumns.cite property to true
289 // so they will be filtered and displayed in citekeysview_
290 for (std::vector<std::string>::const_iterator ccit = citekeys.begin();
291 ccit != citekeys.end(); ++ccit) {
294 for (Gtk::TreeModel::const_iterator cbit =
295 (allListStore_->children()).begin();
296 cbit != (allListStore_->children()).end(); ++cbit) {
298 if ((*cbit)[bibColumns.name] == (*ccit)) {
300 (*cbit)[bibColumns.cite] = true;
301 allListStore_->move(cbit,
302 (allListStore_->children()).end());
307 // It wasn't in the list of keys, but to support
308 // working on a document away from the bibtex file
309 // we should keep it anyway.
310 Gtk::TreeModel::iterator iter = allListStore_->append();
311 (*iter)[bibColumns.name] = Glib::convert(*ccit, "UTF-8", "ISO-8859-1");
312 (*iter)[bibColumns.cite] = true;
313 (*iter)[bibColumns.bib_order] = ++bib_order;
314 (*iter)[bibColumns.info] = Glib::convert(
315 biblio::getInfo(theMap,*ccit), "UTF-8", "ISO-8859-1");
321 void GCitation::update()
327 info_->set_text(""); // Clear Info field
329 // Initialise style tab widgets
330 beforeentry_->set_text(Glib::locale_to_utf8(
331 controller().params().getSecOptions()));
332 afterentry_->set_text(Glib::locale_to_utf8(
333 controller().params().getOptions()));
338 // Deactivate all buttons
339 upbutton_->set_sensitive(false);
340 downbutton_->set_sensitive(false);
341 removebutton_->set_sensitive(false);
342 addbutton_->set_sensitive(false);
344 set_search_buttons();
351 Gtk::TreeModel::iterator src =
352 citeselection_->get_selected();
353 Gtk::TreeModel::iterator dest = src;
355 if(--dest == (citeFilter_->children()).begin())
356 upbutton_->set_sensitive(false);
358 src = citeFilter_->convert_iter_to_child_iter(src);
359 dest = citeFilter_->convert_iter_to_child_iter(dest);
360 allListStore_->iter_swap(src, dest);
363 downbutton_->set_sensitive(true);
367 void GCitation::down()
369 Gtk::TreeModel::iterator src =
370 citeselection_->get_selected();
371 Gtk::TreeModel::iterator dest = src;
372 // Avoid slow operator-- by using an extra variable
373 Gtk::TreeModel::iterator endtest = ++dest;
375 if(++endtest == (citeFilter_->children()).end())
376 downbutton_->set_sensitive(false);
378 src = citeFilter_->convert_iter_to_child_iter(src);
379 dest = citeFilter_->convert_iter_to_child_iter(dest);
380 allListStore_->iter_swap(src, dest);
383 upbutton_->set_sensitive(true);
387 void GCitation::add()
389 Gtk::TreeModel::iterator iter = bibselection_->get_selected();
392 Gtk::TreeModel::iterator next_iter = iter;
394 // Select the right key in bibkeysview_ afterwards
395 if(++next_iter == (bibFilter_->children()).end()) {
396 if(iter != (bibFilter_->children()).begin()) {
397 bibselection_->select(--iter);
399 } else { // bibkeysview_ will be left empty...
400 addbutton_->set_sensitive(false);
403 bibselection_->select(next_iter);
406 iter = bibFilter_->convert_iter_to_child_iter(iter);
407 iter = bibSort_->convert_iter_to_child_iter(iter);
408 (*iter)[bibColumns.cite] = true;
410 // Move key to the right position
411 // If a cite key is selected, move bib key to the position above
412 // Otherwise to the last position in citekeysview_
413 Gtk::TreeModel::iterator cite_iter(citeselection_->get_selected());
415 cite_iter = citeFilter_->convert_iter_to_child_iter(cite_iter);
417 cite_iter = (allListStore_->children()).end();
419 allListStore_->move(iter,cite_iter);
421 // Highlight and scroll to newly inserted key
422 iter = citeFilter_->convert_child_iter_to_iter(iter);
423 citeselection_->select(iter);
424 citekeysview_->scroll_to_row(Gtk::TreePath(iter));
427 removebutton_->set_sensitive(true);
428 set_search_buttons();
435 void GCitation::remove()
437 Gtk::TreeModel::iterator iter(citeselection_->get_selected());
440 Gtk::TreeModel::iterator next_iter(iter);
442 if(++next_iter == (citeFilter_->children()).end()) {
443 if(iter != (citeFilter_->children()).begin()) {
444 citeselection_->select(--iter);
447 } else { // citekeysview_ will be left empty...
448 removebutton_->set_sensitive(false);
452 citeselection_->select(next_iter);
456 // Get an iterator to allListStore_
457 iter = citeFilter_->convert_iter_to_child_iter(iter);
458 (*iter)[bibColumns.cite] = false;
460 // Highlight and scroll to newly inserted key
461 iter = bibSort_->convert_child_iter_to_iter(iter);
462 iter = bibFilter_->convert_child_iter_to_iter(iter);
463 bibselection_->select(iter);
464 bibkeysview_->scroll_to_row(Gtk::TreePath(iter));
467 addbutton_->set_sensitive(true);
468 set_search_buttons();
472 void GCitation::cite_selected()
474 Gtk::TreeModel::iterator iter =
475 citeselection_->get_selected();
478 info_->set_text((*iter)[bibColumns.info]);
479 removebutton_->set_sensitive(true);
481 // Set sensitivity of Up/Down buttons
482 if (iter == (citeFilter_->children()).begin()) {
483 upbutton_->set_sensitive(false);
485 upbutton_->set_sensitive(true);
488 if (++iter == (citeFilter_->children()).end()) {
489 downbutton_->set_sensitive(false);
491 downbutton_->set_sensitive(true);
496 removebutton_->set_sensitive(false);
498 // Set sensitivity of Up/Down buttons
499 upbutton_->set_sensitive(false);
500 downbutton_->set_sensitive(false);
506 void GCitation::bib_selected()
508 Gtk::TreeModel::iterator iter =
509 bibselection_->get_selected();
512 info_->set_text((*iter)[bibColumns.info]);
513 addbutton_->set_sensitive(true);
516 addbutton_->set_sensitive(false);
520 void GCitation::apply()
522 vector<biblio::CiteStyle> const & styles =
523 ControlCitation::getCiteStyles();
525 int const choice = stylecombo_->get_active_row_number();
526 style_ = stylecombo_->get_active_row_number();
528 bool const full = authorcheck_->get_active();
529 bool const force = uppercasecheck_->get_active();
531 string const command =
532 biblio::CitationStyle(styles[choice], full, force)
535 Gtk::TreeNodeChildren children(citeFilter_->children());
539 for (Gtk::TreeModel::const_iterator cit=children.begin();
540 cit!=children.end(); ++cit) {
542 string item(support::trim(Glib::convert(
543 static_cast<Glib::ustring>((*cit)[bibColumns.name]),
544 "ISO-8859-1", "UTF-8")));
552 controller().params().setCmdName(command);
553 controller().params().setContents(citekeys);
555 controller().params().setSecOptions(Glib::locale_from_utf8(beforeentry_->get_text()));
556 controller().params().setOptions(Glib::locale_from_utf8(afterentry_->get_text()));
561 void GCitation::find(biblio::Direction dir)
563 biblio::InfoMap const & theMap = controller().bibkeysInfo();
564 std::vector<std::string> bibkeys;
566 biblio::Search const type = regexpcheck_->get_active()
567 ? biblio::REGEX : biblio::SIMPLE;
569 vector<string>::const_iterator start;
571 bool const casesens = casecheck_->get_active();
572 string const str = Glib::locale_from_utf8(findentry_->get_text());
574 Gtk::TreeModel::iterator iter;
575 Gtk::TreeModel::Children::difference_type sel = 0;
577 for (iter = (bibFilter_->children()).begin();
578 iter != (bibFilter_->children()).end(); ++iter) {
580 bibkeys.push_back(Glib::locale_from_utf8(
581 (*iter)[bibColumns.name]));
584 iter = bibselection_->get_selected();
587 (bibFilter_->children()).begin(), iter);
589 start = bibkeys.begin();
592 Gtk::TreeModel::Children::size_type(sel) < bibkeys.size())
593 std::advance(start, sel);
595 // Find the NEXT instance...
596 if (dir == biblio::FORWARD)
599 vector<string>::const_iterator cit =
600 biblio::searchKeys(theMap, bibkeys, str,
601 start, type, dir, casesens);
603 if (cit == bibkeys.end()) {
604 if (dir == biblio::FORWARD) {
605 start = bibkeys.begin();
608 start = bibkeys.end();
612 cit = biblio::searchKeys(theMap, bibkeys, str,
613 start, type, dir, casesens);
615 if (cit == bibkeys.end()) {
619 vector<string>::const_iterator bibstart = bibkeys.begin();
620 vector<string>::difference_type const found =
621 std::distance(bibstart, cit);
626 iter = (bibFilter_->children()).begin();
627 std::advance(iter, found);
629 // Highlight and scroll to the key that was found
630 bibselection_->select(iter);
631 bibkeysview_->set_cursor(Gtk::TreePath(iter));
632 bibkeysview_->scroll_to_row(Gtk::TreePath(iter));
636 void GCitation::set_search_buttons()
638 bool val = findentry_->get_text_length()
639 && !(bibFilter_->children()).empty();
640 backbutton_->set_sensitive(val);
641 forwardbutton_->set_sensitive(val);
644 void GCitation::previous()
646 find(biblio::BACKWARD);
650 void GCitation::next()
652 find(biblio::FORWARD);
656 void GCitation::bibkeysview_activated(const Gtk::TreeModel::Path&, Gtk::TreeViewColumn*)
661 } // namespace frontend