]> git.lyx.org Git - features.git/blobdiff - src/frontends/qt4/GuiCitation.cpp
reduce line noise
[features.git] / src / frontends / qt4 / GuiCitation.cpp
index 94ce98800117a0bfd69881370fb1fa1776aab96f..975b470d62ac193c3a97a449dc6ebda6a7c31579 100644 (file)
 
 #include "debug.h"
 #include "gettext.h"
-#include "frontend_helpers.h"
 #include "qt_helpers.h"
+#include "Buffer.h"
+#include "BufferParams.h"
 
 #include "support/lstrings.h"
 #include "support/docstring.h"
 
+#include "insets/InsetCommand.h"
+
 #include <vector>
 #include <string>
 
 
 #undef KeyPress
 
+#include <boost/regex.hpp>
+
 #include <algorithm>
 #include <string>
 #include <vector>
 
-using std::vector;
 using std::string;
+using std::vector;
+using std::pair;
+
+namespace lyx {
+namespace frontend {
+
+static vector<biblio::CiteStyle> citeStyles_;
 
 
 template<typename String>
@@ -64,22 +75,11 @@ static vector<lyx::docstring> to_docstring_vector(QStringList const & qlist)
 }
 
 
-namespace lyx {
-namespace frontend {
-
-///////////////////////////////////////////////////////////////////////
-//
-// GuiCitationDialog
-//
-///////////////////////////////////////////////////////////////////////
-
-
-GuiCitationDialog::GuiCitationDialog(Dialog & dialog, GuiCitation * form)
-       : Dialog::View(dialog, _("Citation")), form_(form)
+GuiCitation::GuiCitation(LyXView & lv)
+       : GuiCommand(lv, "citation")
 {
        setupUi(this);
-
-       setWindowTitle(toqstr("LyX: " + getTitle()));
+       setViewTitle(_("Citation"));
 
        connect(citationStyleCO, SIGNAL(activated(int)),
                this, SLOT(changed()));
@@ -87,49 +87,44 @@ GuiCitationDialog::GuiCitationDialog(Dialog & dialog, GuiCitation * form)
                this, SLOT(changed()));
        connect(forceuppercaseCB, SIGNAL(clicked()),
                this, SLOT(changed()));
-       connect(textBeforeED, SIGNAL(textChanged(const QString&)),
+       connect(textBeforeED, SIGNAL(textChanged(QString)),
                this, SLOT(changed()));
-       connect(textAfterED, SIGNAL(textChanged(const QString&)),
+       connect(textAfterED, SIGNAL(textChanged(QString)),
                this, SLOT(changed()));
        connect(clearPB, SIGNAL(clicked()),
                findLE, SLOT(clear()));
        connect(this, SIGNAL(rejected()), this, SLOT(cleanUp()));
 
-       selectionManager = 
-               new GuiSelectionManager(availableLV, selectedLV, 
-                                     addPB, deletePB, upPB, downPB, 
-                                     form_->available(), form_->selected());
+       selectionManager = new GuiSelectionManager(availableLV, selectedLV, 
+                       addPB, deletePB, upPB, downPB, available(), selected());
        connect(selectionManager, SIGNAL(selectionChanged()),
                this, SLOT(setCitedKeys()));
        connect(selectionManager, SIGNAL(updateHook()),
                this, SLOT(updateDialog()));
        connect(selectionManager, SIGNAL(okHook()),
-                                       this, SLOT(on_okPB_clicked()));
+               this, SLOT(on_okPB_clicked()));
 
+       bc().setPolicy(ButtonPolicy::NoRepeatedApplyReadOnlyPolicy);
 }
 
 
-GuiCitationDialog::~GuiCitationDialog()
-{}
-
-
-void GuiCitationDialog::cleanUp() 
+void GuiCitation::cleanUp() 
 {
-       form_->clearSelection();
-       form_->clearParams();
+       clearSelection();
+       clearParams();
        close();
 }
 
 
-void GuiCitationDialog::closeEvent(QCloseEvent * e)
+void GuiCitation::closeEvent(QCloseEvent * e)
 {
-       form_->clearSelection();
-       form_->clearParams();
-       e->accept();
+       clearSelection();
+       clearParams();
+       GuiDialog::closeEvent(e);
 }
 
 
-void GuiCitationDialog::apply()
+void GuiCitation::applyView()
 {
        int  const choice = std::max(0, citationStyleCO->currentIndex());
        style_ = choice;
@@ -139,19 +134,20 @@ void GuiCitationDialog::apply()
        QString const before = textBeforeED->text();
        QString const after = textAfterED->text();
 
-       form_->apply(choice, full, force, before, after);
+       apply(choice, full, force, before, after);
 }
 
 
-void GuiCitationDialog::hide()
+void GuiCitation::hideView()
 {
-       form_->clearParams();
+       clearParams();
        accept();
 }
 
 
-void GuiCitationDialog::show()
+void GuiCitation::showView()
 {
+       init();
        findLE->clear();
        availableLV->setFocus();
        QDialog::show();
@@ -160,55 +156,56 @@ void GuiCitationDialog::show()
 }
 
 
-bool GuiCitationDialog::isVisible() const
+bool GuiCitation::isVisibleView() const
 {
        return QDialog::isVisible();
 }
 
 
-void GuiCitationDialog::on_okPB_clicked()
+void GuiCitation::on_okPB_clicked()
 {
-       apply();
-       form_->clearSelection();
-       hide();
+       applyView();
+       clearSelection();
+       hideView();
 }
 
 
-void GuiCitationDialog::on_cancelPB_clicked()
+void GuiCitation::on_cancelPB_clicked()
 {
-       form_->clearSelection();
-       hide();
+       clearSelection();
+       hideView();
 }
 
 
-void GuiCitationDialog::on_applyPB_clicked()
+void GuiCitation::on_applyPB_clicked()
 {
-       apply();
+       applyView();
 }
 
 
-void GuiCitationDialog::on_restorePB_clicked()
+void GuiCitation::on_restorePB_clicked()
 {
-       form_->init();
-       update();
+       init();
+       updateView();
 }
 
 
-void GuiCitationDialog::update()
+void GuiCitation::updateView()
 {
+       init();
        fillFields();
        fillEntries();
        updateDialog();
 }
 
 
-//The main point of separating this out is that the fill*() methods
-//called in update() do not need to be called for INTERNAL updates,
-//such as when addPB is pressed, as the list of fields, entries, etc,
-//will not have changed. At the moment, however, the division between
-//fillStyles() and updateStyles() doesn't lend itself to dividing the
-//two methods, though they should be divisible.
-void GuiCitationDialog::updateDialog()
+// The main point of separating this out is that the fill*() methods
+// called in update() do not need to be called for INTERNAL updates,
+// such as when addPB is pressed, as the list of fields, entries, etc,
+// will not have changed. At the moment, however, the division between
+// fillStyles() and updateStyles() doesn't lend itself to dividing the
+// two methods, though they should be divisible.
+void GuiCitation::updateDialog()
 {
        if (selectionManager->selectedFocused()) { 
                if (selectedLV->selectionModel()->selectedIndexes().isEmpty())
@@ -223,16 +220,16 @@ void GuiCitationDialog::updateDialog()
        }
        setButtons();
 
-       textBeforeED->setText(form_->textBefore());
-       textAfterED->setText(form_->textAfter());
+       textBeforeED->setText(textBefore());
+       textAfterED->setText(textAfter());
        fillStyles();
        updateStyle();
 }
 
 
-void GuiCitationDialog::updateStyle()
+void GuiCitation::updateStyle()
 {
-       biblio::CiteEngine const engine = form_->getEngine();
+       biblio::CiteEngine const engine = getEngine();
        bool const natbib_engine =
                engine == biblio::ENGINE_NATBIB_AUTHORYEAR ||
                engine == biblio::ENGINE_NATBIB_NUMERICAL;
@@ -249,11 +246,10 @@ void GuiCitationDialog::updateStyle()
        citationStyleCO->setEnabled(!basic_engine && haveSelection);
        citationStyleLA->setEnabled(!basic_engine && haveSelection);
 
-       string const & command = form_->params().getCmdName();
+       string const & command = params_.getCmdName();
 
        // Find the style of the citekeys
-       vector<biblio::CiteStyle> const & styles =
-               ControlCitation::getCiteStyles();
+       vector<biblio::CiteStyle> const & styles = citeStyles_;
        biblio::CitationStyle const cs(command);
 
        vector<biblio::CiteStyle>::const_iterator cit =
@@ -280,13 +276,13 @@ void GuiCitationDialog::updateStyle()
 //This one needs to be called whenever citationStyleCO needs
 //to be updated---and this would be on anything that changes the
 //selection in selectedLV, or on a general update.
-void GuiCitationDialog::fillStyles()
+void GuiCitation::fillStyles()
 {
        int const oldIndex = citationStyleCO->currentIndex();
 
        citationStyleCO->clear();
 
-       QStringList selected_keys = form_->selected()->stringList();
+       QStringList selected_keys = selected()->stringList();
        if (selected_keys.empty()) {
                citationStyleCO->setEnabled(false);
                citationStyleLA->setEnabled(false);
@@ -300,10 +296,9 @@ void GuiCitationDialog::fillStyles()
        if (!selectedLV->selectionModel()->selectedIndexes().empty())
                curr = selectedLV->selectionModel()->selectedIndexes()[0].row();
 
-       QStringList sty = form_->citationStyles(curr);
+       QStringList sty = citationStyles(curr);
 
-       bool const basic_engine =
-                       (form_->getEngine() == biblio::ENGINE_BASIC);
+       bool const basic_engine = (getEngine() == biblio::ENGINE_BASIC);
 
        citationStyleCO->setEnabled(!sty.isEmpty() && !basic_engine);
        citationStyleLA->setEnabled(!sty.isEmpty() && !basic_engine);
@@ -318,12 +313,12 @@ void GuiCitationDialog::fillStyles()
 }
 
 
-void GuiCitationDialog::fillFields()
+void GuiCitation::fillFields()
 {
        fieldsCO->blockSignals(true);
        int const oldIndex = fieldsCO->currentIndex();
        fieldsCO->clear();
-       QStringList const & fields = form_->getFieldsAsQStringList();
+       QStringList const & fields = getFieldsAsQStringList();
        fieldsCO->insertItem(0, qt_("All Fields"));
        fieldsCO->insertItem(1, qt_("Keys"));
        fieldsCO->insertItems(2, fields);
@@ -333,12 +328,12 @@ void GuiCitationDialog::fillFields()
 }
 
 
-void GuiCitationDialog::fillEntries()
+void GuiCitation::fillEntries()
 {
        entriesCO->blockSignals(true);
        int const oldIndex = entriesCO->currentIndex();
        entriesCO->clear();
-       QStringList const & entries = form_->getEntriesAsQStringList();
+       QStringList const & entries = getEntriesAsQStringList();
        entriesCO->insertItem(0, qt_("All Entry Types"));
        entriesCO->insertItems(1, entries);
        if (oldIndex != -1 && oldIndex < entriesCO->count())
@@ -347,14 +342,14 @@ void GuiCitationDialog::fillEntries()
 }
 
 
-bool GuiCitationDialog::isSelected(const QModelIndex & idx)
+bool GuiCitation::isSelected(const QModelIndex & idx)
 {
        QString const str = idx.data().toString();
-       return form_->selected()->stringList().contains(str);
+       return selected()->stringList().contains(str);
 }
 
 
-void GuiCitationDialog::setButtons()
+void GuiCitation::setButtons()
 {
        selectionManager->update();
        int const srows = selectedLV->model()->rowCount();
@@ -363,27 +358,21 @@ void GuiCitationDialog::setButtons()
 }
 
 
-void GuiCitationDialog::updateInfo(QModelIndex const & idx)
+void GuiCitation::updateInfo(QModelIndex const & idx)
 {
        if (idx.isValid()) {
-               QString const keytxt = form_->getKeyInfo(idx.data().toString());
+               QString const keytxt = getKeyInfo(idx.data().toString());
                infoML->document()->setPlainText(keytxt);
        } else
                infoML->document()->clear();
 }
 
 
-void GuiCitationDialog::setCitedKeys() 
-{
-       form_->setCitedKeys();
-}
-
-
-void GuiCitationDialog::findText(QString const & text, bool reset)
+void GuiCitation::findText(QString const & text, bool reset)
 {
        //"All Fields" and "Keys" are the first two
        int index = fieldsCO->currentIndex() - 2; 
-       vector<docstring> const & fields = form_->availableFields();
+       vector<docstring> const & fields = availableFields();
        docstring field;
        
        if (index <= -1 || index >= int(fields.size()))
@@ -397,7 +386,7 @@ void GuiCitationDialog::findText(QString const & text, bool reset)
        
        //"All Entry Types" is first.
        index = entriesCO->currentIndex() - 1; 
-       vector<docstring> const & entries = form_->availableEntries();
+       vector<docstring> const & entries = availableEntries();
        docstring entryType;
        if (index < 0 || index >= int(entries.size()))
                entryType = from_ascii("");
@@ -406,7 +395,7 @@ void GuiCitationDialog::findText(QString const & text, bool reset)
        
        bool const case_sentitive = caseCB->checkState();
        bool const reg_exp = regexCB->checkState();
-       form_->findKey(text, onlyKeys, field, entryType, 
+       findKey(text, onlyKeys, field, entryType, 
                       case_sentitive, reg_exp, reset);
        //FIXME
        //It'd be nice to save and restore the current selection in 
@@ -417,19 +406,19 @@ void GuiCitationDialog::findText(QString const & text, bool reset)
 }
 
 
-void GuiCitationDialog::on_fieldsCO_currentIndexChanged(int /*index*/)
+void GuiCitation::on_fieldsCO_currentIndexChanged(int /*index*/)
 {
        findText(findLE->text(), true);
 }
 
 
-void GuiCitationDialog::on_entriesCO_currentIndexChanged(int /*index*/)
+void GuiCitation::on_entriesCO_currentIndexChanged(int /*index*/)
 {
        findText(findLE->text(), true);
 }
 
 
-void GuiCitationDialog::on_findLE_textChanged(const QString & text)
+void GuiCitation::on_findLE_textChanged(const QString & text)
 {
        clearPB->setDisabled(text.isEmpty());
        if (text.isEmpty())
@@ -438,53 +427,41 @@ void GuiCitationDialog::on_findLE_textChanged(const QString & text)
 }
 
 
-void GuiCitationDialog::on_caseCB_stateChanged(int)
+void GuiCitation::on_caseCB_stateChanged(int)
 {
        findText(findLE->text());
 }
 
 
-void GuiCitationDialog::on_regexCB_stateChanged(int)
+void GuiCitation::on_regexCB_stateChanged(int)
 {
        findText(findLE->text());
 }
 
 
-void GuiCitationDialog::changed()
+void GuiCitation::changed()
 {
        fillStyles();
        setButtons();
 }
 
-///////////////////////////////////////////////////////////////////////
-//
-// GuiCitation
-//
-///////////////////////////////////////////////////////////////////////
-
-GuiCitation::GuiCitation(GuiDialog & parent)
-       : ControlCitation(parent)
-{
-}
-
 
 void GuiCitation::apply(int const choice, bool const full, bool const force,
-                     QString before, QString after)
+       QString before, QString after)
 {
        if (cited_keys_.isEmpty())
                return;
 
-       vector<biblio::CiteStyle> const & styles =
-               ControlCitation::getCiteStyles();
+       vector<biblio::CiteStyle> const & styles = citeStyles_;
 
        string const command =
                biblio::CitationStyle(styles[choice], full, force)
                .asLatexStr();
 
-       params().setCmdName(command);
-       params()["key"] = qstring_to_ucs4(cited_keys_.join(","));
-       params()["before"] = qstring_to_ucs4(before);
-       params()["after"] = qstring_to_ucs4(after);
+       params_.setCmdName(command);
+       params_["key"] = qstring_to_ucs4(cited_keys_.join(","));
+       params_["before"] = qstring_to_ucs4(before);
+       params_["after"] = qstring_to_ucs4(after);
        dispatchParams();
 }
 
@@ -498,22 +475,13 @@ void GuiCitation::clearSelection()
 
 QString GuiCitation::textBefore()
 {
-       return toqstr(params()["before"]);
+       return toqstr(params_["before"]);
 }
 
 
 QString GuiCitation::textAfter()
 {
-       return toqstr(params()["after"]);
-}
-
-
-bool GuiCitation::initialiseParams(std::string const & data)
-{
-       if (!ControlCitation::initialiseParams(data))
-               return false;
-       init();
-       return true;
+       return toqstr(params_["after"]);
 }
 
 
@@ -524,7 +492,7 @@ void GuiCitation::init()
        available_model_.setStringList(all_keys_);
 
        // Ditto for the keys cited in this inset
-       QString str = toqstr(params()["key"]);
+       QString str = toqstr(params_["key"]);
        if (str.isEmpty())
                cited_keys_.clear();
        else
@@ -545,7 +513,7 @@ void GuiCitation::findKey(QString const & str, bool only_keys,
        // Reset last_searched_string in case of changed option.
        if (last_case_sensitive != case_sensitive
                || last_reg_exp != reg_exp) {
-                       LYXERR(Debug::GUI) << "GuiCitation::findKey: optimisation disabled!" << std::endl;
+                       LYXERR(Debug::GUI, "GuiCitation::findKey: optimisation disabled!");
                last_searched_string.clear();
        }
        // save option for next search.
@@ -600,7 +568,7 @@ QStringList GuiCitation::getEntriesAsQStringList()
 QStringList GuiCitation::citationStyles(int sel)
 {
        docstring const key = qstring_to_ucs4(cited_keys_[sel]);
-       return to_qstring_list(getCiteStrings(key));
+       return to_qstring_list(bibkeysInfo_.getCiteStrings(key, buffer()));
 }
 
 
@@ -609,11 +577,173 @@ QString GuiCitation::getKeyInfo(QString const & sel)
        return toqstr(getInfo(qstring_to_ucs4(sel)));
 }
 
+
 void GuiCitation::setCitedKeys() 
 {
        cited_keys_ = selected_model_.stringList();
 }
 
+
+bool GuiCitation::initialiseParams(string const & data)
+{
+       InsetCommandMailer::string2params(lfun_name_, data, params_);
+
+       biblio::CiteEngine const engine = buffer().params().getEngine();
+
+       bool use_styles = engine != biblio::ENGINE_BASIC;
+
+       bibkeysInfo_.fillWithBibKeys(&buffer());
+       
+       if (citeStyles_.empty())
+               citeStyles_ = biblio::getCiteStyles(engine);
+       else {
+               if ((use_styles && citeStyles_.size() == 1) ||
+                   (!use_styles && citeStyles_.size() != 1))
+                       citeStyles_ = biblio::getCiteStyles(engine);
+       }
+
+       return true;
+}
+
+
+void GuiCitation::clearParams()
+{
+       params_.clear();
+       bibkeysInfo_.clear();
+}
+
+
+vector<docstring> const GuiCitation::availableKeys() const
+{
+       return bibkeysInfo_.getKeys();
+}
+
+
+vector<docstring> const GuiCitation::availableFields() const
+{
+       return bibkeysInfo_.getFields();
+}
+
+
+vector<docstring> const GuiCitation::availableEntries() const
+{
+       return bibkeysInfo_.getEntries();
+}
+
+
+void GuiCitation::filterByEntryType(
+       vector<docstring> & keyVector, docstring entryType) 
+{
+       if (entryType.empty())
+               return;
+       
+       vector<docstring>::iterator it = keyVector.begin();
+       vector<docstring>::iterator end = keyVector.end();
+       
+       vector<docstring> result;
+       for (; it != end; ++it) {
+               docstring const key = *it;
+               BiblioInfo::const_iterator cit = bibkeysInfo_.find(key);
+               if (cit == bibkeysInfo_.end())
+                       continue;
+               if (cit->second.entryType == entryType)
+                       result.push_back(key);
+       }
+       keyVector = result;
+}
+
+
+biblio::CiteEngine GuiCitation::getEngine() const
+{
+       return buffer().params().getEngine();
+}
+
+
+docstring GuiCitation::getInfo(docstring const & key) const
+{
+       if (bibkeysInfo_.empty())
+               return docstring();
+
+       return bibkeysInfo_.getInfo(key);
+}
+
+
+// Escape special chars.
+// All characters are literals except: '.|*?+(){}[]^$\'
+// These characters are literals when preceded by a "\", which is done here
+// @todo: This function should be moved to support, and then the test in tests
+//        should be moved there as well.
+static docstring escape_special_chars(docstring const & expr)
+{
+       // Search for all chars '.|*?+(){}[^$]\'
+       // Note that '[' and '\' must be escaped.
+       // This is a limitation of boost::regex, but all other chars in BREs
+       // are assumed literal.
+       static const boost::regex reg("[].|*?+(){}^$\\[\\\\]");
+
+       // $& is a perl-like expression that expands to all
+       // of the current match
+       // The '$' must be prefixed with the escape character '\' for
+       // boost to treat it as a literal.
+       // Thus, to prefix a matched expression with '\', we use:
+       // FIXME: UNICODE
+       return from_utf8(boost::regex_replace(to_utf8(expr), reg, "\\\\$&"));
+}
+
+
+vector<docstring> GuiCitation::searchKeys(
+       vector<docstring> const & keys_to_search, bool only_keys,
+       docstring const & search_expression, docstring field,
+       bool case_sensitive, bool regex)
+{
+       vector<docstring> foundKeys;
+
+       docstring expr = support::trim(search_expression);
+       if (expr.empty())
+               return foundKeys;
+
+       if (!regex)
+               // We must escape special chars in the search_expr so that
+               // it is treated as a simple string by boost::regex.
+               expr = escape_special_chars(expr);
+
+       boost::regex reg_exp(to_utf8(expr), case_sensitive ?
+               boost::regex_constants::normal : boost::regex_constants::icase);
+
+       vector<docstring>::const_iterator it = keys_to_search.begin();
+       vector<docstring>::const_iterator end = keys_to_search.end();
+       for (; it != end; ++it ) {
+               BiblioInfo::const_iterator info = bibkeysInfo_.find(*it);
+               if (info == bibkeysInfo_.end())
+                       continue;
+               
+               BibTeXInfo const & kvm = info->second;
+               string data;
+               if (only_keys)
+                       data = to_utf8(*it);
+               else if (field.empty())
+                       data = to_utf8(*it) + ' ' + to_utf8(kvm.allData);
+               else if (kvm.hasField(field))
+                       data = to_utf8(kvm.getValueForField(field));
+               
+               if (data.empty())
+                       continue;
+
+               try {
+                       if (boost::regex_search(data, reg_exp))
+                               foundKeys.push_back(*it);
+               }
+               catch (boost::regex_error &) {
+                       return vector<docstring>();
+               }
+       }
+       return foundKeys;
+}
+
+
+Dialog * createGuiCitation(LyXView & lv) { return new GuiCitation(lv); }
+
+
 } // namespace frontend
 } // namespace lyx