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;
70 GCitation::GCitation(Dialog & parent)
71 : GViewCB<ControlCitation, GViewGladeB>(parent, _("Citation"), false)
75 void GCitation::doBuild()
77 string const gladeName = findGladeFile("citation");
78 xml_ = Gnome::Glade::Xml::create(gladeName);
80 xml_->get_widget("Restore", restorebutton_);
81 setRestore(restorebutton_);
82 xml_->get_widget("Cancel", cancelbutton_);
83 setCancel(cancelbutton_);
84 xml_->get_widget("Apply", applybutton_);
85 setApply(applybutton_);
86 xml_->get_widget("OK", okbutton_);
89 xml_->get_widget("Remove", removebutton_);
90 xml_->get_widget("Add", addbutton_);
91 xml_->get_widget("Back", backbutton_);
92 xml_->get_widget("Forward", forwardbutton_);
93 xml_->get_widget("Up", upbutton_);
94 xml_->get_widget("Down", downbutton_);
96 xml_->get_widget("CiteKeys", citekeysview_);
97 xml_->get_widget("BibKeys", bibkeysview_);
98 xml_->get_widget("Info", infoview_);
99 xml_->get_widget("CaseSensitive", casecheck_);
101 xml_->get_widget("SearchCite", citeradio_);
102 xml_->get_widget("SearchBib", bibradio_);
103 xml_->get_widget("SearchString", findentry_);
104 xml_->get_widget("CaseSensitive", casecheck_);
105 xml_->get_widget("RegularExpression", regexpcheck_);
107 xml_->get_widget("StyleLabel", stylelabel_);
108 xml_->get_widget("Style", stylecombo_);
109 xml_->get_widget("TextBeforeLabel", beforelabel_);
110 xml_->get_widget("TextBefore", beforeentry_);
111 xml_->get_widget("TextAfter", afterentry_);
112 xml_->get_widget("FullAuthorList", authorcheck_);
113 xml_->get_widget("ForceUpperCase", uppercasecheck_);
115 info_ = Gtk::TextBuffer::create();
116 infoview_->set_buffer(info_);
118 allListStore_ = Gtk::ListStore::create(bibColumns);
120 Gtk::TreeModel::Path rootpath; //required for gtkmm < 2.6
122 citekeysview_->append_column(_("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();
128 bibkeysview_->append_column(_("BibKeys"), bibColumns.name);
129 bibSort_ = Gtk::TreeModelSort::create(allListStore_);
130 bibSort_->set_sort_column(bibColumns.bib_order, Gtk::SORT_ASCENDING );
131 bibFilter_ = Gtk::TreeModelFilter::create(bibSort_, rootpath);
132 bibFilter_->set_visible_func(&GCitation::bib_visible);
133 bibkeysview_->set_model(bibFilter_);
134 bibselection_ = bibkeysview_->get_selection();
136 styleStore_ = Gtk::ListStore::create(styleColumns);
137 stylecombo_->set_model(styleStore_);
139 upbutton_->signal_clicked().connect(
140 sigc::mem_fun(*this, &GCitation::up));
141 downbutton_->signal_clicked().connect(
142 sigc::mem_fun(*this, &GCitation::down));
143 addbutton_->signal_clicked().connect(
144 sigc::mem_fun(*this, &GCitation::add));
145 removebutton_->signal_clicked().connect(
146 sigc::mem_fun(*this, &GCitation::remove));
147 backbutton_->signal_clicked().connect(
148 sigc::mem_fun(*this, &GCitation::previous));
149 forwardbutton_->signal_clicked().connect(
150 sigc::mem_fun(*this, &GCitation::next));
152 bibradio_->signal_toggled().connect(
153 sigc::mem_fun(*this, &GCitation::set_search_buttons));
154 citeradio_->signal_toggled().connect(
155 sigc::mem_fun(*this, &GCitation::set_search_buttons));
156 findentry_->signal_changed().connect(
157 sigc::mem_fun(*this, &GCitation::set_search_buttons));
159 bibkeysview_->signal_row_activated().connect(
160 sigc::mem_fun(*this, &GCitation::bibkeysview_activated));
161 bibselection_->signal_changed().connect(
162 sigc::mem_fun(*this, &GCitation::bib_selected));
164 citeselection_->signal_changed().connect(
165 sigc::mem_fun(*this, &GCitation::cite_selected));
167 beforeentry_->signal_changed().connect(
168 sigc::mem_fun(*this, &GCitation::enable_apply));
169 afterentry_->signal_changed().connect(
170 sigc::mem_fun(*this, &GCitation::enable_apply));
171 stylecombo_->signal_changed().connect(
172 sigc::mem_fun(*this, &GCitation::enable_apply));
173 authorcheck_->signal_toggled().connect(
174 sigc::mem_fun(*this, &GCitation::enable_apply));
175 uppercasecheck_->signal_toggled().connect(
176 sigc::mem_fun(*this, &GCitation::enable_apply));
181 void GCitation::enable_apply() {
182 // if we passed !applylock_ directly as an argument, the restore button
183 // would be activated
184 if (!applylock_ && !(citeFilter_->children()).empty())
189 void GCitation::fill_styles()
191 if ((citeFilter_->children()).empty()) {
192 stylecombo_->set_sensitive(false);
193 stylelabel_->set_sensitive(false);
197 int orig = stylecombo_->get_active_row_number();
199 Gtk::TreeModel::iterator iter = citeselection_->get_selected();
201 iter = (citeFilter_->children()).begin();
202 string key = Glib::locale_from_utf8((*iter)[bibColumns.name]);
204 std::vector<string> const & sty = controller().getCiteStrings(key);
206 biblio::CiteEngine const engine = controller().getEngine();
207 bool const basic_engine = engine == biblio::ENGINE_BASIC;
209 stylecombo_->set_sensitive(!sty.empty() && !basic_engine);
210 stylelabel_->set_sensitive(!sty.empty() && !basic_engine);
212 vector<string>::const_iterator it = sty.begin();
213 vector<string>::const_iterator const end = sty.end();
215 styleStore_->clear();
216 for (; it != end; ++it) {
217 Gtk::TreeModel::iterator iter2 = styleStore_->append();
218 (*iter2)[styleColumns.name] = Glib::locale_to_utf8(*it);
222 stylecombo_->set_active(orig);
226 void GCitation::update_style()
228 biblio::CiteEngine const engine = controller().getEngine();
229 bool const natbib_engine =
230 engine == biblio::ENGINE_NATBIB_AUTHORYEAR ||
231 engine == biblio::ENGINE_NATBIB_NUMERICAL;
232 bool const basic_engine = engine == biblio::ENGINE_BASIC;
234 authorcheck_->set_sensitive(natbib_engine);
235 uppercasecheck_->set_sensitive(natbib_engine);
236 beforeentry_->set_sensitive(!basic_engine);
237 beforelabel_->set_sensitive(!basic_engine);
239 string const & command = controller().params().getCmdName();
241 // Find the style of the citekeys
242 vector<biblio::CiteStyle> const & styles =
243 ControlCitation::getCiteStyles();
244 biblio::CitationStyle const cs(command);
246 vector<biblio::CiteStyle>::const_iterator cit =
247 std::find(styles.begin(), styles.end(), cs.style);
249 //restore the latest natbib style
250 if (style_ >= 0 && Gtk::TreeModel::Children::size_type(style_) <
251 (styleStore_->children()).size())
252 stylecombo_->set_active(style_);
254 stylecombo_->unset_active();
256 authorcheck_->set_active(false);
257 uppercasecheck_->set_active(false);
259 if (cit != styles.end()) {
260 stylecombo_->set_active(cit - styles.begin());
261 authorcheck_->set_active(cs.full);
262 uppercasecheck_->set_active(cs.forceUCase);
267 void GCitation::update_contents()
269 // Make a list of all available bibliography keys
270 biblio::InfoMap const & theMap = controller().bibkeysInfo();
271 std::vector<std::string> bibkeys = biblio::getKeys(theMap);
272 std::vector<std::string> citekeys = support::getVectorFromString(
273 controller().params().getContents());
276 allListStore_->clear();
278 for (std::vector<std::string>::const_iterator cit = bibkeys.begin();
279 cit != bibkeys.end(); ++cit) {
281 Gtk::TreeModel::iterator iter = allListStore_->append();
282 (*iter)[bibColumns.name] = Glib::locale_to_utf8(*cit);
283 (*iter)[bibColumns.cite] = false; //reset state
284 (*iter)[bibColumns.bib_order] = ++bib_order;
285 (*iter)[bibColumns.info] = Glib::locale_to_utf8(
286 biblio::getInfo(theMap,*cit));
289 // Now mark cite keys by setting their bibColumns.cite property to true
290 // so they will be filtered and displayed in citekeysview_
291 for (std::vector<std::string>::const_iterator ccit = citekeys.begin();
292 ccit != citekeys.end(); ++ccit) {
295 for (Gtk::TreeModel::const_iterator cbit =
296 (allListStore_->children()).begin();
297 cbit != (allListStore_->children()).end(); ++cbit) {
299 if ((*cbit)[bibColumns.name] == (*ccit)) {
301 (*cbit)[bibColumns.cite] = true;
302 allListStore_->move(cbit,
303 (allListStore_->children()).end());
308 // It wasn't in the list of keys, but to support
309 // working on a document away from the bibtex file
310 // we should keep it anyway.
311 Gtk::TreeModel::iterator iter = allListStore_->append();
312 (*iter)[bibColumns.name] = Glib::locale_to_utf8(*ccit);
313 (*iter)[bibColumns.cite] = true;
314 (*iter)[bibColumns.bib_order] = ++bib_order;
315 (*iter)[bibColumns.info] = Glib::locale_to_utf8(
316 biblio::getInfo(theMap,*ccit));
322 void GCitation::update()
328 info_->set_text(""); // Clear Info field
330 // Initialise style tab widgets
331 beforeentry_->set_text(Glib::locale_to_utf8(
332 controller().params().getSecOptions()));
333 afterentry_->set_text(Glib::locale_to_utf8(
334 controller().params().getOptions()));
339 // Deactivate all buttons
340 upbutton_->set_sensitive(false);
341 downbutton_->set_sensitive(false);
342 removebutton_->set_sensitive(false);
343 addbutton_->set_sensitive(false);
345 set_search_buttons();
352 Gtk::TreeModel::iterator src =
353 citeselection_->get_selected();
354 Gtk::TreeModel::iterator dest = src;
356 if(--dest == (citeFilter_->children()).begin())
357 upbutton_->set_sensitive(false);
359 src = citeFilter_->convert_iter_to_child_iter(src);
360 dest = citeFilter_->convert_iter_to_child_iter(dest);
361 allListStore_->iter_swap(src, dest);
364 downbutton_->set_sensitive(true);
368 void GCitation::down()
370 Gtk::TreeModel::iterator src =
371 citeselection_->get_selected();
372 Gtk::TreeModel::iterator dest = src;
373 // Avoid slow operator-- by using an extra variable
374 Gtk::TreeModel::iterator endtest = ++dest;
376 if(++endtest == (citeFilter_->children()).end())
377 downbutton_->set_sensitive(false);
379 src = citeFilter_->convert_iter_to_child_iter(src);
380 dest = citeFilter_->convert_iter_to_child_iter(dest);
381 allListStore_->iter_swap(src, dest);
384 upbutton_->set_sensitive(true);
388 void GCitation::add()
390 Gtk::TreeModel::iterator iter = bibselection_->get_selected();
393 Gtk::TreeModel::iterator next_iter = iter;
395 // Select the right key in bibkeysview_ afterwards
396 if(++next_iter == (bibFilter_->children()).end()) {
397 if(iter != (bibFilter_->children()).begin()) {
398 bibselection_->select(--iter);
400 } else { // bibkeysview_ will be left empty...
401 addbutton_->set_sensitive(false);
404 bibselection_->select(next_iter);
407 iter = bibFilter_->convert_iter_to_child_iter(iter);
408 iter = bibSort_->convert_iter_to_child_iter(iter);
409 (*iter)[bibColumns.cite] = true;
411 // Move key to the right position
412 // If a cite key is selected, move bib key to the position above
413 // Otherwise to the last position in citekeysview_
414 Gtk::TreeModel::iterator cite_iter(citeselection_->get_selected());
416 cite_iter = citeFilter_->convert_iter_to_child_iter(cite_iter);
418 cite_iter = (allListStore_->children()).end();
420 allListStore_->move(iter,cite_iter);
422 // Highlight and scroll to newly inserted key
423 iter = citeFilter_->convert_child_iter_to_iter(iter);
424 citeselection_->select(iter);
425 citekeysview_->scroll_to_row(Gtk::TreePath(iter));
428 removebutton_->set_sensitive(true);
429 set_search_buttons();
436 void GCitation::remove()
438 Gtk::TreeModel::iterator iter(citeselection_->get_selected());
441 Gtk::TreeModel::iterator next_iter(iter);
443 if(++next_iter == (citeFilter_->children()).end()) {
444 if(iter != (citeFilter_->children()).begin()) {
445 citeselection_->select(--iter);
448 } else { // citekeysview_ will be left empty...
449 removebutton_->set_sensitive(false);
453 citeselection_->select(next_iter);
457 // Get an iterator to allListStore_
458 iter = citeFilter_->convert_iter_to_child_iter(iter);
459 (*iter)[bibColumns.cite] = false;
461 // Highlight and scroll to newly inserted key
462 iter = bibSort_->convert_child_iter_to_iter(iter);
463 iter = bibFilter_->convert_child_iter_to_iter(iter);
464 bibselection_->select(iter);
465 bibkeysview_->scroll_to_row(Gtk::TreePath(iter));
468 addbutton_->set_sensitive(true);
469 set_search_buttons();
473 void GCitation::cite_selected()
475 Gtk::TreeModel::iterator iter =
476 citeselection_->get_selected();
479 info_->set_text((*iter)[bibColumns.info]);
480 removebutton_->set_sensitive(true);
482 // Set sensitivity of Up/Down buttons
483 if (iter == (citeFilter_->children()).begin()) {
484 upbutton_->set_sensitive(false);
486 upbutton_->set_sensitive(true);
489 if (++iter == (citeFilter_->children()).end()) {
490 downbutton_->set_sensitive(false);
492 downbutton_->set_sensitive(true);
497 removebutton_->set_sensitive(false);
499 // Set sensitivity of Up/Down buttons
500 upbutton_->set_sensitive(false);
501 downbutton_->set_sensitive(false);
507 void GCitation::bib_selected()
509 Gtk::TreeModel::iterator iter =
510 bibselection_->get_selected();
513 info_->set_text((*iter)[bibColumns.info]);
514 addbutton_->set_sensitive(true);
517 addbutton_->set_sensitive(false);
521 void GCitation::apply()
523 vector<biblio::CiteStyle> const & styles =
524 ControlCitation::getCiteStyles();
526 int const choice = stylecombo_->get_active_row_number();
527 style_ = stylecombo_->get_active_row_number();
529 bool const full = authorcheck_->get_active();
530 bool const force = uppercasecheck_->get_active();
532 string const command =
533 biblio::CitationStyle(styles[choice], full, force)
536 Gtk::TreeNodeChildren children(citeFilter_->children());
540 for (Gtk::TreeModel::const_iterator cit=children.begin();
541 cit!=children.end(); ++cit) {
543 string item(support::trim(Glib::locale_from_utf8((*cit)[bibColumns.name])));
551 controller().params().setCmdName(command);
552 controller().params().setContents(citekeys);
554 controller().params().setSecOptions(Glib::locale_from_utf8(beforeentry_->get_text()));
555 controller().params().setOptions(Glib::locale_from_utf8(afterentry_->get_text()));
560 void GCitation::find(biblio::Direction dir)
562 biblio::InfoMap const & theMap = controller().bibkeysInfo();
563 std::vector<std::string> bibkeys;
565 biblio::Search const type = regexpcheck_->get_active()
566 ? biblio::REGEX : biblio::SIMPLE;
568 vector<string>::const_iterator start;
570 bool search_cite = citeradio_->get_active();
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;
578 for (iter = (citeFilter_->children()).begin();
579 iter != (citeFilter_->children()).end(); ++iter) {
581 bibkeys.push_back(Glib::locale_from_utf8(
582 (*iter)[bibColumns.name]));
585 iter = citeselection_->get_selected();
587 sel = std::distance((citeFilter_->children()).begin(), iter);
589 for (iter = (bibFilter_->children()).begin();
590 iter != (bibFilter_->children()).end(); ++iter) {
592 bibkeys.push_back(Glib::locale_from_utf8(
593 (*iter)[bibColumns.name]));
596 iter = bibselection_->get_selected();
599 (bibFilter_->children()).begin(), iter);
602 start = bibkeys.begin();
605 Gtk::TreeModel::Children::size_type(sel) < bibkeys.size())
606 std::advance(start, sel);
608 bool is_cite = !search_cite;
609 while(is_cite != search_cite) {
611 // Find the NEXT instance...
612 if (dir == biblio::FORWARD)
615 vector<string>::const_iterator cit =
616 biblio::searchKeys(theMap, bibkeys, str,
617 start, type, dir, casesens);
619 if (cit == bibkeys.end()) {
620 if (dir == biblio::FORWARD) {
621 start = bibkeys.begin();
624 start = bibkeys.end();
628 cit = biblio::searchKeys(theMap, bibkeys, str,
629 start, type, dir, casesens);
631 if (cit == bibkeys.end()) {
635 vector<string>::const_iterator bibstart = bibkeys.begin();
636 vector<string>::difference_type const found =
637 std::distance(bibstart, cit);
643 iter = (citeFilter_->children()).begin();
645 iter = (bibFilter_->children()).begin();
646 std::advance(iter, found);
647 is_cite = (*iter)[bibColumns.cite];
650 // Highlight and scroll to the key that was found
652 citeselection_->select(iter);
653 citekeysview_->set_cursor(Gtk::TreePath(iter));
654 citekeysview_->scroll_to_row(Gtk::TreePath(iter));
657 bibselection_->select(iter);
658 bibkeysview_->set_cursor(Gtk::TreePath(iter));
659 bibkeysview_->scroll_to_row(Gtk::TreePath(iter));
664 void GCitation::set_search_buttons()
666 bool val = findentry_->get_text_length() && (
667 (citeradio_->get_active() && !(citeFilter_->children()).empty())
668 || (bibradio_->get_active() && !(bibFilter_->children()).empty())
670 backbutton_->set_sensitive(val);
671 forwardbutton_->set_sensitive(val);
674 void GCitation::previous()
676 find(biblio::BACKWARD);
680 void GCitation::next()
682 find(biblio::FORWARD);
686 void GCitation::bibkeysview_activated(const Gtk::TreeModel::Path&, Gtk::TreeViewColumn*)
691 } // namespace frontend