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("SearchString", findentry_);
102 xml_->get_widget("CaseSensitive", casecheck_);
103 xml_->get_widget("RegularExpression", regexpcheck_);
105 xml_->get_widget("StyleLabel", stylelabel_);
106 xml_->get_widget("Style", stylecombo_);
107 xml_->get_widget("TextBeforeLabel", beforelabel_);
108 xml_->get_widget("TextBefore", beforeentry_);
109 xml_->get_widget("TextAfter", afterentry_);
110 xml_->get_widget("FullAuthorList", authorcheck_);
111 xml_->get_widget("ForceUpperCase", uppercasecheck_);
113 info_ = Gtk::TextBuffer::create();
114 infoview_->set_buffer(info_);
116 allListStore_ = Gtk::ListStore::create(bibColumns);
118 Gtk::TreeModel::Path rootpath; //required for gtkmm < 2.6
120 citekeysview_->append_column(_("CiteKeys"), bibColumns.name);
121 citeFilter_ = Gtk::TreeModelFilter::create(allListStore_, rootpath);
122 citeFilter_->set_visible_column(bibColumns.cite);
123 citekeysview_->set_model(citeFilter_);
124 citeselection_ = citekeysview_->get_selection();
126 bibkeysview_->append_column(_("BibKeys"), bibColumns.name);
127 bibSort_ = Gtk::TreeModelSort::create(allListStore_);
128 bibSort_->set_sort_column(bibColumns.bib_order, Gtk::SORT_ASCENDING );
129 bibFilter_ = Gtk::TreeModelFilter::create(bibSort_, rootpath);
130 bibFilter_->set_visible_func(&GCitation::bib_visible);
131 bibkeysview_->set_model(bibFilter_);
132 bibselection_ = bibkeysview_->get_selection();
134 styleStore_ = Gtk::ListStore::create(styleColumns);
135 stylecombo_->set_model(styleStore_);
137 upbutton_->signal_clicked().connect(
138 sigc::mem_fun(*this, &GCitation::up));
139 downbutton_->signal_clicked().connect(
140 sigc::mem_fun(*this, &GCitation::down));
141 addbutton_->signal_clicked().connect(
142 sigc::mem_fun(*this, &GCitation::add));
143 removebutton_->signal_clicked().connect(
144 sigc::mem_fun(*this, &GCitation::remove));
145 backbutton_->signal_clicked().connect(
146 sigc::mem_fun(*this, &GCitation::previous));
147 forwardbutton_->signal_clicked().connect(
148 sigc::mem_fun(*this, &GCitation::next));
150 findentry_->signal_changed().connect(
151 sigc::mem_fun(*this, &GCitation::set_search_buttons));
153 bibkeysview_->signal_row_activated().connect(
154 sigc::mem_fun(*this, &GCitation::bibkeysview_activated));
155 bibselection_->signal_changed().connect(
156 sigc::mem_fun(*this, &GCitation::bib_selected));
158 citeselection_->signal_changed().connect(
159 sigc::mem_fun(*this, &GCitation::cite_selected));
161 beforeentry_->signal_changed().connect(
162 sigc::mem_fun(*this, &GCitation::enable_apply));
163 afterentry_->signal_changed().connect(
164 sigc::mem_fun(*this, &GCitation::enable_apply));
165 stylecombo_->signal_changed().connect(
166 sigc::mem_fun(*this, &GCitation::enable_apply));
167 authorcheck_->signal_toggled().connect(
168 sigc::mem_fun(*this, &GCitation::enable_apply));
169 uppercasecheck_->signal_toggled().connect(
170 sigc::mem_fun(*this, &GCitation::enable_apply));
175 void GCitation::enable_apply() {
176 // if we passed !applylock_ directly as an argument, the restore button
177 // would be activated
178 if (!applylock_ && !(citeFilter_->children()).empty())
183 void GCitation::fill_styles()
185 if ((citeFilter_->children()).empty()) {
186 stylecombo_->set_sensitive(false);
187 stylelabel_->set_sensitive(false);
191 int orig = stylecombo_->get_active_row_number();
193 Gtk::TreeModel::iterator iter = citeselection_->get_selected();
195 iter = (citeFilter_->children()).begin();
196 string key = Glib::locale_from_utf8((*iter)[bibColumns.name]);
198 std::vector<string> const & sty = controller().getCiteStrings(key);
200 biblio::CiteEngine const engine = controller().getEngine();
201 bool const basic_engine = engine == biblio::ENGINE_BASIC;
203 stylecombo_->set_sensitive(!sty.empty() && !basic_engine);
204 stylelabel_->set_sensitive(!sty.empty() && !basic_engine);
206 vector<string>::const_iterator it = sty.begin();
207 vector<string>::const_iterator const end = sty.end();
209 styleStore_->clear();
210 for (; it != end; ++it) {
211 Gtk::TreeModel::iterator iter2 = styleStore_->append();
212 (*iter2)[styleColumns.name] = Glib::locale_to_utf8(*it);
216 stylecombo_->set_active(orig);
220 void GCitation::update_style()
222 biblio::CiteEngine const engine = controller().getEngine();
223 bool const natbib_engine =
224 engine == biblio::ENGINE_NATBIB_AUTHORYEAR ||
225 engine == biblio::ENGINE_NATBIB_NUMERICAL;
226 bool const basic_engine = engine == biblio::ENGINE_BASIC;
228 authorcheck_->set_sensitive(natbib_engine);
229 uppercasecheck_->set_sensitive(natbib_engine);
230 beforeentry_->set_sensitive(!basic_engine);
231 beforelabel_->set_sensitive(!basic_engine);
233 string const & command = controller().params().getCmdName();
235 // Find the style of the citekeys
236 vector<biblio::CiteStyle> const & styles =
237 ControlCitation::getCiteStyles();
238 biblio::CitationStyle const cs(command);
240 vector<biblio::CiteStyle>::const_iterator cit =
241 std::find(styles.begin(), styles.end(), cs.style);
243 //restore the latest natbib style
244 if (style_ >= 0 && Gtk::TreeModel::Children::size_type(style_) <
245 (styleStore_->children()).size())
246 stylecombo_->set_active(style_);
248 stylecombo_->unset_active();
250 authorcheck_->set_active(false);
251 uppercasecheck_->set_active(false);
253 if (cit != styles.end()) {
254 stylecombo_->set_active(cit - styles.begin());
255 authorcheck_->set_active(cs.full);
256 uppercasecheck_->set_active(cs.forceUCase);
261 void GCitation::update_contents()
263 // Make a list of all available bibliography keys
264 biblio::InfoMap const & theMap = controller().bibkeysInfo();
265 std::vector<std::string> bibkeys = biblio::getKeys(theMap);
266 std::vector<std::string> citekeys = support::getVectorFromString(
267 controller().params().getContents());
270 allListStore_->clear();
272 for (std::vector<std::string>::const_iterator cit = bibkeys.begin();
273 cit != bibkeys.end(); ++cit) {
275 Gtk::TreeModel::iterator iter = allListStore_->append();
276 // ENCODING, FIXME: assuming ISO-8859 only for key name and info fields
277 // This is a hack to avoid a crash when populating the dialog from bibtex
278 // files containing non-ASCII characters.
279 (*iter)[bibColumns.name] = Glib::convert(*cit, "UTF-8", "ISO-8859-1");
280 (*iter)[bibColumns.cite] = false; //reset state
281 (*iter)[bibColumns.bib_order] = ++bib_order;
282 (*iter)[bibColumns.info] = Glib::convert(biblio::getInfo(theMap,*cit), "UTF-8", "ISO-8859-1");
285 // Now mark cite keys by setting their bibColumns.cite property to true
286 // so they will be filtered and displayed in citekeysview_
287 for (std::vector<std::string>::const_iterator ccit = citekeys.begin();
288 ccit != citekeys.end(); ++ccit) {
291 for (Gtk::TreeModel::const_iterator cbit =
292 (allListStore_->children()).begin();
293 cbit != (allListStore_->children()).end(); ++cbit) {
295 if ((*cbit)[bibColumns.name] == (*ccit)) {
297 (*cbit)[bibColumns.cite] = true;
298 allListStore_->move(cbit,
299 (allListStore_->children()).end());
304 // It wasn't in the list of keys, but to support
305 // working on a document away from the bibtex file
306 // we should keep it anyway.
307 Gtk::TreeModel::iterator iter = allListStore_->append();
308 (*iter)[bibColumns.name] = Glib::convert(*ccit, "UTF-8", "ISO-8859-1");
309 (*iter)[bibColumns.cite] = true;
310 (*iter)[bibColumns.bib_order] = ++bib_order;
311 (*iter)[bibColumns.info] = Glib::convert(
312 biblio::getInfo(theMap,*ccit), "UTF-8", "ISO-8859-1");
318 void GCitation::update()
324 info_->set_text(""); // Clear Info field
326 // Initialise style tab widgets
327 beforeentry_->set_text(Glib::locale_to_utf8(
328 controller().params().getSecOptions()));
329 afterentry_->set_text(Glib::locale_to_utf8(
330 controller().params().getOptions()));
335 // Deactivate all buttons
336 upbutton_->set_sensitive(false);
337 downbutton_->set_sensitive(false);
338 removebutton_->set_sensitive(false);
339 addbutton_->set_sensitive(false);
341 set_search_buttons();
348 Gtk::TreeModel::iterator src =
349 citeselection_->get_selected();
350 Gtk::TreeModel::iterator dest = src;
352 if(--dest == (citeFilter_->children()).begin())
353 upbutton_->set_sensitive(false);
355 src = citeFilter_->convert_iter_to_child_iter(src);
356 dest = citeFilter_->convert_iter_to_child_iter(dest);
357 allListStore_->iter_swap(src, dest);
360 downbutton_->set_sensitive(true);
364 void GCitation::down()
366 Gtk::TreeModel::iterator src =
367 citeselection_->get_selected();
368 Gtk::TreeModel::iterator dest = src;
369 // Avoid slow operator-- by using an extra variable
370 Gtk::TreeModel::iterator endtest = ++dest;
372 if(++endtest == (citeFilter_->children()).end())
373 downbutton_->set_sensitive(false);
375 src = citeFilter_->convert_iter_to_child_iter(src);
376 dest = citeFilter_->convert_iter_to_child_iter(dest);
377 allListStore_->iter_swap(src, dest);
380 upbutton_->set_sensitive(true);
384 void GCitation::add()
386 Gtk::TreeModel::iterator iter = bibselection_->get_selected();
389 Gtk::TreeModel::iterator next_iter = iter;
391 // Select the right key in bibkeysview_ afterwards
392 if(++next_iter == (bibFilter_->children()).end()) {
393 if(iter != (bibFilter_->children()).begin()) {
394 bibselection_->select(--iter);
396 } else { // bibkeysview_ will be left empty...
397 addbutton_->set_sensitive(false);
400 bibselection_->select(next_iter);
403 iter = bibFilter_->convert_iter_to_child_iter(iter);
404 iter = bibSort_->convert_iter_to_child_iter(iter);
405 (*iter)[bibColumns.cite] = true;
407 // Move key to the right position
408 // If a cite key is selected, move bib key to the position above
409 // Otherwise to the last position in citekeysview_
410 Gtk::TreeModel::iterator cite_iter(citeselection_->get_selected());
412 cite_iter = citeFilter_->convert_iter_to_child_iter(cite_iter);
414 cite_iter = (allListStore_->children()).end();
416 allListStore_->move(iter,cite_iter);
418 // Highlight and scroll to newly inserted key
419 iter = citeFilter_->convert_child_iter_to_iter(iter);
420 citeselection_->select(iter);
421 citekeysview_->scroll_to_row(Gtk::TreePath(iter));
424 removebutton_->set_sensitive(true);
425 set_search_buttons();
432 void GCitation::remove()
434 Gtk::TreeModel::iterator iter(citeselection_->get_selected());
437 Gtk::TreeModel::iterator next_iter(iter);
439 if(++next_iter == (citeFilter_->children()).end()) {
440 if(iter != (citeFilter_->children()).begin()) {
441 citeselection_->select(--iter);
444 } else { // citekeysview_ will be left empty...
445 removebutton_->set_sensitive(false);
449 citeselection_->select(next_iter);
453 // Get an iterator to allListStore_
454 iter = citeFilter_->convert_iter_to_child_iter(iter);
455 (*iter)[bibColumns.cite] = false;
457 // Highlight and scroll to newly inserted key
458 iter = bibSort_->convert_child_iter_to_iter(iter);
459 iter = bibFilter_->convert_child_iter_to_iter(iter);
460 bibselection_->select(iter);
461 bibkeysview_->scroll_to_row(Gtk::TreePath(iter));
464 addbutton_->set_sensitive(true);
465 set_search_buttons();
469 void GCitation::cite_selected()
471 Gtk::TreeModel::iterator iter =
472 citeselection_->get_selected();
475 info_->set_text((*iter)[bibColumns.info]);
476 removebutton_->set_sensitive(true);
478 // Set sensitivity of Up/Down buttons
479 if (iter == (citeFilter_->children()).begin()) {
480 upbutton_->set_sensitive(false);
482 upbutton_->set_sensitive(true);
485 if (++iter == (citeFilter_->children()).end()) {
486 downbutton_->set_sensitive(false);
488 downbutton_->set_sensitive(true);
493 removebutton_->set_sensitive(false);
495 // Set sensitivity of Up/Down buttons
496 upbutton_->set_sensitive(false);
497 downbutton_->set_sensitive(false);
503 void GCitation::bib_selected()
505 Gtk::TreeModel::iterator iter =
506 bibselection_->get_selected();
509 info_->set_text((*iter)[bibColumns.info]);
510 addbutton_->set_sensitive(true);
513 addbutton_->set_sensitive(false);
517 void GCitation::apply()
519 vector<biblio::CiteStyle> const & styles =
520 ControlCitation::getCiteStyles();
522 int const choice = stylecombo_->get_active_row_number();
523 style_ = stylecombo_->get_active_row_number();
525 bool const full = authorcheck_->get_active();
526 bool const force = uppercasecheck_->get_active();
528 string const command =
529 biblio::CitationStyle(styles[choice], full, force)
532 Gtk::TreeNodeChildren children(citeFilter_->children());
536 for (Gtk::TreeModel::const_iterator cit=children.begin();
537 cit!=children.end(); ++cit) {
539 string item(support::trim(Glib::convert(
540 static_cast<Glib::ustring>((*cit)[bibColumns.name]),
541 "ISO-8859-1", "UTF-8")));
549 controller().params().setCmdName(command);
550 controller().params().setContents(citekeys);
552 controller().params().setSecOptions(Glib::locale_from_utf8(beforeentry_->get_text()));
553 controller().params().setOptions(Glib::locale_from_utf8(afterentry_->get_text()));
558 void GCitation::find(biblio::Direction dir)
560 biblio::InfoMap const & theMap = controller().bibkeysInfo();
561 std::vector<std::string> bibkeys;
563 biblio::Search const type = regexpcheck_->get_active()
564 ? biblio::REGEX : biblio::SIMPLE;
566 vector<string>::const_iterator start;
568 bool const casesens = casecheck_->get_active();
569 string const str = Glib::locale_from_utf8(findentry_->get_text());
571 Gtk::TreeModel::iterator iter;
572 Gtk::TreeModel::Children::difference_type sel = 0;
574 for (iter = (bibFilter_->children()).begin();
575 iter != (bibFilter_->children()).end(); ++iter) {
577 bibkeys.push_back(Glib::locale_from_utf8(
578 (*iter)[bibColumns.name]));
581 iter = bibselection_->get_selected();
584 (bibFilter_->children()).begin(), iter);
586 start = bibkeys.begin();
589 Gtk::TreeModel::Children::size_type(sel) < bibkeys.size())
590 std::advance(start, sel);
592 // Find the NEXT instance...
593 if (dir == biblio::FORWARD)
596 vector<string>::const_iterator cit =
597 biblio::searchKeys(theMap, bibkeys, str,
598 start, type, dir, casesens);
600 if (cit == bibkeys.end()) {
601 if (dir == biblio::FORWARD) {
602 start = bibkeys.begin();
605 start = bibkeys.end();
609 cit = biblio::searchKeys(theMap, bibkeys, str,
610 start, type, dir, casesens);
612 if (cit == bibkeys.end()) {
616 vector<string>::const_iterator bibstart = bibkeys.begin();
617 vector<string>::difference_type const found =
618 std::distance(bibstart, cit);
623 iter = (bibFilter_->children()).begin();
624 std::advance(iter, found);
626 // Highlight and scroll to the key that was found
627 bibselection_->select(iter);
628 bibkeysview_->set_cursor(Gtk::TreePath(iter));
629 bibkeysview_->scroll_to_row(Gtk::TreePath(iter));
633 void GCitation::set_search_buttons()
635 bool val = findentry_->get_text_length()
636 && !(bibFilter_->children()).empty();
637 backbutton_->set_sensitive(val);
638 forwardbutton_->set_sensitive(val);
641 void GCitation::previous()
643 find(biblio::BACKWARD);
647 void GCitation::next()
649 find(biblio::FORWARD);
653 void GCitation::bibkeysview_activated(const Gtk::TreeModel::Path&, Gtk::TreeViewColumn*)
658 } // namespace frontend