"Fossies" - the Fresh Open Source Software Archive

Member "cb2bib-2.0.1/src/c2bReferenceList.cpp" (12 Feb 2021, 25133 Bytes) of package /linux/privat/cb2bib-2.0.1.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "c2bReferenceList.cpp" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 2.0.0_vs_2.0.1.

    1 /***************************************************************************
    2  *   Copyright (C) 2004-2021 by Pere Constans
    3  *   constans@molspaces.com
    4  *   cb2Bib version 2.0.1. Licensed under the GNU GPL version 3.
    5  *   See the LICENSE file that comes with this distribution.
    6  ***************************************************************************/
    7 #include "c2bReferenceList.h"
    8 
    9 #include "c2b.h"
   10 #include "c2bBibParser.h"
   11 #include "c2bCoreCiter.h"
   12 #include "c2bRLWebSearchSettings.h"
   13 #include "c2bSettings.h"
   14 #include "c2bTextBrowser.h"
   15 #include "c2bTextEdit.h"
   16 #include "c2bUtils.h"
   17 
   18 #include <bibSearcher.h>
   19 
   20 #include <QHeaderView>
   21 #include <QMenu>
   22 #include <QScrollBar>
   23 #include <QTimer>
   24 
   25 
   26 class TreeWidgetItem : public QTreeWidgetItem
   27 {
   28     // Reimplement sorting
   29 public:
   30     explicit TreeWidgetItem(const QStringList& strings) : QTreeWidgetItem(strings) {}
   31     bool operator<(const QTreeWidgetItem& other) const
   32     {
   33         const int sortCol(treeWidget()->sortColumn());
   34         const QString str(c2bUtils::toAscii(text(sortCol), c2bUtils::Collation));
   35         const QString other_str(c2bUtils::toAscii(other.text(sortCol), c2bUtils::Collation));
   36         return str < other_str;
   37     }
   38 };
   39 
   40 
   41 c2bReferenceList::c2bReferenceList(c2bTextEdit* ed, c2bTextBrowser* br, QWidget* parentw) : QWidget(parentw)
   42 {
   43     ui.setupUi(this);
   44     _editorP = ed;
   45     _browserP = br;
   46     _citerP = new c2bCoreCiter(this);
   47     _settingsP = c2bSettingsP;
   48     _settingsP->setDefaultValue("c2bReferenceList/SearchEngine", "https://www.google.com/search?ie=UTF-8&q=");
   49     _settingsP->setDefaultValue("c2bReferenceList/SearchEngineAddQuotes", false);
   50     setupFilterBar();
   51 
   52     _key_index = 0;
   53     _id_index = 1;
   54     _year_index = 2;
   55     _journal_index = 3;
   56     _author_index = 4;
   57     _title_index = 5;
   58     QStringList header;
   59     header.append(tr("Key"));
   60     header.append(tr("ID"));
   61     header.append(tr("Year"));
   62     header.append(tr("Journal"));
   63     header.append(tr("Author"));
   64     header.append(tr("Title"));
   65     ui.listView->sortItems(_key_index, Qt::AscendingOrder);
   66     ui.listView->setHeaderLabels(header);
   67     ui.listView->hideColumn(_id_index);
   68     ui.listView->setContextMenuPolicy(Qt::ActionsContextMenu);
   69 
   70     citeEntryAction = new QAction(this);
   71     citeEntryAction->setText(tr("Cite Selected Entries"));
   72     _settingsP->setKeysequence("Shortcuts/Editor/", citeEntryAction);
   73     connect(citeEntryAction, SIGNAL(triggered()), this, SLOT(citeEntry()));
   74     ui.listView->addAction(citeEntryAction);
   75 
   76     c2bUtils::addSeparator(ui.listView);
   77     openFileAction = new QAction(this);
   78     openFileAction->setText(tr("Open Document File"));
   79     openFileAction->setStatusTip(tr("Open document file"));
   80     _settingsP->setKeysequence("Shortcuts/Editor/", openFileAction);
   81     connect(openFileAction, SIGNAL(triggered()), this, SLOT(openFile()));
   82     ui.listView->addAction(openFileAction);
   83 
   84     openUrlAction = new QAction(this);
   85     openUrlAction->setText(tr("Open Document URL"));
   86     openUrlAction->setStatusTip(tr("Open document URL"));
   87     _settingsP->setKeysequence("Shortcuts/Editor/", openUrlAction);
   88     connect(openUrlAction, SIGNAL(triggered()), this, SLOT(openUrl()));
   89     ui.listView->addAction(openUrlAction);
   90 
   91     openDOIAction = new QAction(this);
   92     openDOIAction->setText(tr("Browse Reference by DOI"));
   93     openDOIAction->setStatusTip(tr("Browse reference by DOI"));
   94     _settingsP->setKeysequence("Shortcuts/Editor/", openDOIAction);
   95     connect(openDOIAction, SIGNAL(triggered()), this, SLOT(openDOI()));
   96     ui.listView->addAction(openDOIAction);
   97 
   98     c2bUtils::addSeparator(ui.listView);
   99     openAuthorsWebSearchAction = new QAction(this);
  100     openAuthorsWebSearchAction->setText(tr("Web Search by Author"));
  101     openAuthorsWebSearchAction->setStatusTip(tr("Web search by Author"));
  102     _settingsP->setKeysequence("Shortcuts/Editor/", openAuthorsWebSearchAction);
  103     connect(openAuthorsWebSearchAction, SIGNAL(triggered()), this, SLOT(openAuthorWebSearch()));
  104     ui.listView->addAction(openAuthorsWebSearchAction);
  105     openTitleWebSearchAction = new QAction(this);
  106     openTitleWebSearchAction->setText(tr("Web Search by Title"));
  107     openTitleWebSearchAction->setStatusTip(tr("Web search by Title"));
  108     _settingsP->setKeysequence("Shortcuts/Editor/", openTitleWebSearchAction);
  109     connect(openTitleWebSearchAction, SIGNAL(triggered()), this, SLOT(openTitleWebSearch()));
  110     ui.listView->addAction(openTitleWebSearchAction);
  111 
  112     c2bUtils::addSeparator(ui.listView);
  113     webSearchSettingsAction = new QAction(this);
  114     webSearchSettingsAction->setText(tr("Web Search Settings"));
  115     webSearchSettingsAction->setStatusTip(tr("Web search settings"));
  116     _settingsP->setKeysequence("Shortcuts/Editor/", webSearchSettingsAction);
  117     connect(webSearchSettingsAction, SIGNAL(triggered()), this, SLOT(webSearchSettings()));
  118     ui.listView->addAction(webSearchSettingsAction);
  119 
  120     c2bUtils::addSeparator(ui.listView);
  121     clearSelectionsAction = new QAction(this);
  122     clearSelectionsAction->setText(tr("Clear Entry Selection"));
  123     clearSelectionsAction->setStatusTip(tr("Clear entry selection"));
  124     _settingsP->setKeysequence("Shortcuts/Editor/", clearSelectionsAction);
  125     connect(clearSelectionsAction, SIGNAL(triggered()), this, SLOT(clearSelections()));
  126     ui.listView->addAction(clearSelectionsAction);
  127 
  128     c2bUtils::addSeparator(ui.listView);
  129     refreshListAction = new QAction(this);
  130     refreshListAction->setShortcut(QKeySequence(QKeySequence::Refresh));
  131     refreshListAction->setText(tr("Refresh List and Browser"));
  132     refreshListAction->setStatusTip(tr("Refresh list and browser"));
  133     connect(refreshListAction, SIGNAL(triggered()), this, SLOT(refreshList()));
  134     ui.listView->addAction(refreshListAction);
  135     connect(ui.listView, SIGNAL(itemActivated(QTreeWidgetItem*,int)), this, SLOT(goToReference(QTreeWidgetItem*)));
  136 
  137     // Actions dependent on selection and availability
  138     itemSelectionChanged();
  139     connect(ui.listView, SIGNAL(itemSelectionChanged()), this, SLOT(itemSelectionChanged()));
  140 
  141     // Browser functionality
  142     _references_html = c2bUtils::fileToString(":/htm/htm/references.html");
  143     _references_html.replace("GET_CB2BIB_VERSION_NUMBER", C2B_VERSION);
  144     _bib_item_html = c2bUtils::fileToString(":/htm/htm/bib_item.html");
  145     QString references_css(c2bUtils::fileToString(_settingsP->fileName("cb2Bib/BrowserCssFile")));
  146     if (references_css.isEmpty())
  147         references_css = c2bUtils::fileToString(":/htm/htm/references.css");
  148     _browserP->document()->setDefaultStyleSheet(references_css);
  149 
  150     openTextLocalSearchAction = new QAction(this);
  151     openTextLocalSearchAction->setText(tr("Local Search for Selected Text"));
  152     openTextLocalSearchAction->setStatusTip(tr("Local search for selected text"));
  153     _settingsP->setKeysequence("Shortcuts/Editor/", openTextLocalSearchAction);
  154     connect(openTextLocalSearchAction, SIGNAL(triggered()), this, SLOT(openTextLocalSearch()));
  155     openTextLocalSearchAction->setEnabled(false);
  156     connect(_browserP, SIGNAL(copyAvailable(bool)), openTextLocalSearchAction, SLOT(setEnabled(bool)));
  157     openTextWebSearchAction = new QAction(this);
  158     openTextWebSearchAction->setText(tr("Web Search for Selected Text"));
  159     openTextWebSearchAction->setStatusTip(tr("Web search for selected text"));
  160     _settingsP->setKeysequence("Shortcuts/Editor/", openTextWebSearchAction);
  161     connect(openTextWebSearchAction, SIGNAL(triggered()), this, SLOT(openTextWebSearch()));
  162     openTextWebSearchAction->setEnabled(false);
  163     connect(_browserP, SIGNAL(copyAvailable(bool)), openTextWebSearchAction, SLOT(setEnabled(bool)));
  164 
  165     QList<QAction*> al = ui.listView->actions();
  166     for (int i = 0; i < 2; ++i)
  167         _browserP->addAction(al.at(i));
  168     _browserP->addAction(openTextLocalSearchAction);
  169     _browserP->addAction(openTextWebSearchAction);
  170     c2bUtils::addSeparator(_browserP);
  171     for (int i = 6; i < al.count(); ++i)
  172         _browserP->addAction(al.at(i));
  173     _browserP->setContextMenuPolicy(Qt::ActionsContextMenu);
  174 
  175     connect(_browserP, SIGNAL(anchorClicked(QUrl)), this, SLOT(openLink(QUrl)));
  176     connect(_browserP, SIGNAL(highlighted(QString)), parentw->parent(), SLOT(showMessage(QString)));
  177 }
  178 
  179 c2bReferenceList::~c2bReferenceList() {}
  180 
  181 
  182 void c2bReferenceList::loadList(const QString& txt, bibSearcher* searcher)
  183 {
  184     QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
  185     c2bBibParser* bpP(c2b::bibParser());
  186     QString references_html(_references_html);
  187     QString references;
  188 
  189     QStringList fields;
  190     fields.append("abstract");
  191     fields.append("author");
  192     fields.append("booktitle");
  193     fields.append("doi");
  194     fields.append("editor");
  195     fields.append("file");
  196     fields.append("journal");
  197     fields.append("pages");
  198     fields.append("title");
  199     fields.append("url");
  200     fields.append("volume");
  201     fields.append("year");
  202     bibReference ref;
  203     bpP->initReferenceParsing(_editorP->editorFilename(), fields, &ref);
  204     const QRegExp initials1("\\b\\w\\b");
  205     const QRegExp initials2("[^\\w\\s]");
  206     const QRegExp nonletters("[^\\w\\s-]");
  207     int ref_counter(0);
  208 
  209     while (bpP->referencesIn(txt, &ref))
  210     {
  211         QString author(ref.anyAuthor());
  212         QString author_long;
  213         if (!author.isEmpty())
  214         {
  215             author = bpP->authorFromBibTeX(author);
  216             author_long = author;
  217             author_long.remove(nonletters);
  218             author_long.replace(" and ", ", ");
  219             c2bUtils::simplifyString(author_long);
  220             author_long += '.';
  221             author.remove(initials1);
  222             author.remove(initials2);
  223             author.replace(" and ", ", ");
  224             c2bUtils::simplifyString(author);
  225         }
  226 
  227         QString title(ref.anyTitle());
  228         c2bUtils::cleanTitle(title, true);
  229 
  230         QString doi(ref.value("doi"));
  231         if (!doi.isEmpty())
  232             if (!doi.startsWith("http"))
  233                 doi = "https://dx.doi.org/" + QUrl::toPercentEncoding(doi);
  234 
  235         const QString file(ref.value("file"));
  236         const QString url(ref.value("url"));
  237         QString link;
  238         if (!file.isEmpty())
  239             link = QDir::cleanPath(file);
  240         else if (!url.isEmpty())
  241             link = url;
  242         else if (!doi.isEmpty())
  243             link = doi;
  244 
  245         QString ID;
  246         ID.setNum(ref_counter + 1);
  247         QString year(ref.value("year"));
  248         const QString abstract(ref.value("abstract"));
  249         const QString journal(ref.anyJournal());
  250         const QString key(ref.citeidName);
  251 
  252         _doiList.append(doi);
  253         _fileList.append(file);
  254         _urlList.append(url);
  255         _positionList.append(ref.positionValue);
  256         QStringList dataList;
  257         dataList.append(key);
  258         dataList.append(ID);
  259         dataList.append(year);
  260         dataList.append(journal);
  261         dataList.append(author);
  262         dataList.append(title);
  263         TreeWidgetItem* qi(new TreeWidgetItem(dataList));
  264         qi->setStatusTip(_journal_index, bpP->fullJournal(journal));
  265         qi->setStatusTip(_author_index, author_long);
  266         qi->setStatusTip(_title_index, title);
  267         ui.listView->insertTopLevelItem(0, qi);
  268 
  269         QString pages(ref.value("pages"));
  270         const QString volume(ref.value("volume"));
  271         if (!pages.isEmpty())
  272         {
  273             if (!volume.isEmpty())
  274                 pages = ", " + pages;
  275             else
  276                 pages = ' ' + pages;
  277         }
  278         if (!year.isEmpty())
  279             year = '(' + year + ").";
  280         QString bib_item_html(_bib_item_html);
  281         bib_item_html.replace("GET_REFERENCE_ANCHOR_ID", ID);
  282         bib_item_html.replace("GET_REFERENCE_ANCHOR_NAME", ID);
  283         bib_item_html.replace("GET_REFERENCE_AUTHOR", author_long);
  284         bib_item_html.replace("GET_REFERENCE_LINK", link);
  285         bib_item_html.replace("GET_REFERENCE_PAGES", pages);
  286         bib_item_html.replace("GET_REFERENCE_SOURCE", journal);
  287         bib_item_html.replace("GET_REFERENCE_TITLE", c2bUtils::toHtmlString(title));
  288         bib_item_html.replace("GET_REFERENCE_VOLUME", volume);
  289         bib_item_html.replace("GET_REFERENCE_YEAR", year);
  290         if (searcher)
  291         {
  292             if (searcher->isSearchSimilar())
  293                 bib_item_html.replace("GET_REFERENCE_ABSTRACT",
  294                                       c2bUtils::toHtmlString(abstract) + searcher->hitHtmlDatum(ref_counter));
  295             else
  296                 bib_item_html.replace("GET_REFERENCE_ABSTRACT",
  297                                       searcher->hitHtmlAbstract(ref_counter) + searcher->hitHtmlDatum(ref_counter));
  298         }
  299         else
  300             bib_item_html.replace("GET_REFERENCE_ABSTRACT", c2bUtils::toHtmlString(abstract));
  301         references += bib_item_html;
  302         ++ref_counter;
  303     }
  304     if (searcher && ref_counter != searcher->hitsCount())
  305         c2bUtils::warn(tr("Mismatch while loading searched references"));
  306 
  307     ui.listView->sortItems(ui.listView->sortColumn(), ui.listView->header()->sortIndicatorOrder());
  308     ui.listView->resizeColumnToContents(_year_index);
  309     references_html.replace("GET_REFERENCES", references);
  310     _browserP->updateHtml(references_html);
  311     QApplication::restoreOverrideCursor();
  312     c2b::showMessage(tr("Parsed %1 references.").arg(ref_counter));
  313 }
  314 
  315 void c2bReferenceList::citeEntry()
  316 {
  317     QStringList keys;
  318     QTreeWidgetItemIterator it(ui.listView, QTreeWidgetItemIterator::Selected | QTreeWidgetItemIterator::NotHidden);
  319     while (*it)
  320     {
  321         if (!(*it)->text(_key_index).isEmpty())
  322             keys.append((*it)->text(_key_index));
  323         ++it;
  324     }
  325     _citerP->cite(keys);
  326 }
  327 
  328 void c2bReferenceList::openDOI()
  329 {
  330     bool zdoi(false);
  331     QTreeWidgetItemIterator it(ui.listView, QTreeWidgetItemIterator::Selected | QTreeWidgetItemIterator::NotHidden);
  332     while (*it)
  333     {
  334         const QString doi(_doiList.at((*it)->text(_id_index).toInt() - 1));
  335         if (!doi.isEmpty())
  336         {
  337             zdoi = true;
  338             c2bUtils::openFile(doi, parentWidget());
  339         }
  340         ++it;
  341     }
  342     if (!zdoi)
  343         c2b::showMessage(tr("No DOI entry among selected references."));
  344 }
  345 
  346 void c2bReferenceList::openFile()
  347 {
  348     bool zfile(false);
  349     QTreeWidgetItemIterator it(ui.listView, QTreeWidgetItemIterator::Selected | QTreeWidgetItemIterator::NotHidden);
  350     while (*it)
  351     {
  352         const QString file(_fileList.at((*it)->text(_id_index).toInt() - 1));
  353         if (!file.isEmpty())
  354         {
  355             zfile = true;
  356             c2bUtils::openFile(file, parentWidget());
  357         }
  358         ++it;
  359     }
  360     if (!zfile)
  361         c2b::showMessage(tr("No file entry among selected references."));
  362 }
  363 
  364 void c2bReferenceList::openUrl()
  365 {
  366     bool zurl(false);
  367     QTreeWidgetItemIterator it(ui.listView, QTreeWidgetItemIterator::Selected | QTreeWidgetItemIterator::NotHidden);
  368     while (*it)
  369     {
  370         const QString url(_urlList.at((*it)->text(_id_index).toInt() - 1));
  371         if (!url.isEmpty())
  372         {
  373             zurl = true;
  374             c2bUtils::openFile(url, parentWidget());
  375         }
  376         ++it;
  377     }
  378     if (!zurl)
  379         c2b::showMessage(tr("No URL entry among selected references."));
  380 }
  381 
  382 void c2bReferenceList::openLink(const QUrl& ln)
  383 {
  384     QString ln_str(QUrl::fromPercentEncoding(ln.toEncoded()));
  385     if (ln_str.isEmpty())
  386         c2b::showMessage(tr("No link available for this reference."));
  387     else if (ln_str.startsWith("Select reference "))
  388         scrollToReference(ln_str.remove(QRegExp("\\D")));
  389     else if (ln_str.contains(QRegExp(":\\d+$")))
  390         emit openFile(ln_str);
  391     else
  392         c2bUtils::openFile(ln_str, parentWidget());
  393 }
  394 
  395 void c2bReferenceList::openAuthorWebSearch()
  396 {
  397     const QString searchEngine(_settingsP->value("c2bReferenceList/SearchEngine").toString());
  398     bool zwebs(false);
  399     QTreeWidgetItemIterator it(ui.listView, QTreeWidgetItemIterator::Selected | QTreeWidgetItemIterator::NotHidden);
  400     while (*it)
  401     {
  402         if (!(*it)->text(_author_index).isEmpty())
  403         {
  404             zwebs = true;
  405             QString webs((*it)->text(_author_index));
  406             webs.remove(',');
  407             webs = searchEngine + webs.simplified();
  408             c2bUtils::openFile(webs, parentWidget());
  409         }
  410         ++it;
  411     }
  412     if (!zwebs)
  413         c2b::showMessage(tr("No author entry among selected references."));
  414 }
  415 
  416 void c2bReferenceList::openTitleWebSearch()
  417 {
  418     const QString searchEngine(_settingsP->value("c2bReferenceList/SearchEngine").toString());
  419     const bool addQuotes(_settingsP->value("c2bReferenceList/SearchEngineAddQuotes").toBool());
  420     bool zwebs(false);
  421     QTreeWidgetItemIterator it(ui.listView, QTreeWidgetItemIterator::Selected | QTreeWidgetItemIterator::NotHidden);
  422     while (*it)
  423     {
  424         if (!(*it)->text(_title_index).isEmpty())
  425         {
  426             zwebs = true;
  427             QString webs((*it)->text(_title_index));
  428             if (addQuotes)
  429                 webs = '\"' + webs + '\"';
  430             webs = searchEngine + webs;
  431             c2bUtils::openFile(webs, parentWidget());
  432         }
  433         ++it;
  434     }
  435     if (!zwebs)
  436         c2b::showMessage(tr("No title entry among selected references."));
  437 }
  438 
  439 void c2bReferenceList::openTextWebSearch()
  440 {
  441     const QString searchEngine(_settingsP->value("c2bReferenceList/SearchEngine").toString());
  442     QString webs(_browserP->textCursor().selectedText());
  443     if (_settingsP->value("c2bReferenceList/SearchEngineAddQuotes").toBool())
  444         webs = '\"' + webs + '\"';
  445     webs = searchEngine + webs;
  446     c2bUtils::openFile(webs, parentWidget());
  447 }
  448 
  449 void c2bReferenceList::webSearchSettings()
  450 {
  451     c2bRLWebSearchSettings searchSettings(this);
  452     searchSettings.exec();
  453 }
  454 
  455 void c2bReferenceList::openTextLocalSearch()
  456 {
  457     const QString text(_browserP->textCursor().selectedText());
  458     const QString fn(_editorP->editorFilename());
  459     c2b::doSearchInFiles(text, fn);
  460 }
  461 
  462 void c2bReferenceList::refreshList()
  463 {
  464     _doiList.clear();
  465     _fileList.clear();
  466     _urlList.clear();
  467     _positionList.clear();
  468     ui.listView->clear();
  469     ui.comboFilter->clearEditText();
  470     loadList(_editorP->toPlainText());
  471 }
  472 
  473 void c2bReferenceList::goToReference(const QString& id)
  474 {
  475     QTextCursor tc(_editorP->textCursor());
  476     tc.setPosition(_positionList.at(id.toInt() - 1));
  477     _editorP->setTextCursor(tc);
  478     _editorP->verticalScrollBar()->setValue(_editorP->verticalScrollBar()->maximum());
  479     _editorP->ensureCursorVisible();
  480 
  481     _browserP->scrollToAnchor(id);
  482     int scrollPosition(_browserP->verticalScrollBar()->value());
  483     _browserP->verticalScrollBar()->setValue(scrollPosition - 10);
  484 }
  485 
  486 void c2bReferenceList::goToReference(const int position)
  487 {
  488     // Maps position to internal reference id. It is needed by the search browser, when a
  489     // citation is edited in the original file. If this file is changed multiple times,
  490     // positions in the search browser get outdated, so the mapping position-id is inexact.
  491     // Thus, search for the closest reference.
  492     int ip(0);
  493     int pdiff_min(1000000);
  494     for (int i = 0; i < _positionList.count(); ++i)
  495     {
  496         int p(_positionList.at(i));
  497         if (p == position)
  498         {
  499             ip = i;
  500             break;
  501         }
  502         int pdiff(abs(p - position));
  503         if (pdiff < pdiff_min)
  504         {
  505             pdiff_min = pdiff;
  506             ip = i;
  507         }
  508     }
  509     QString id;
  510     goToReference(id.setNum(ip + 1));
  511 }
  512 
  513 void c2bReferenceList::goToReference(QTreeWidgetItem* ref)
  514 {
  515     if (ref == 0)
  516         return;
  517     const QString id(ref->text(_id_index));
  518     goToReference(id);
  519 }
  520 
  521 void c2bReferenceList::scrollToReference(const QString& id)
  522 {
  523     if (id.isEmpty())
  524         return;
  525     QList<QTreeWidgetItem*> items(ui.listView->findItems(id, Qt::MatchExactly, 1));
  526     if (items.count() == 0)
  527         return;
  528     QTreeWidgetItem* item(items.at(0));
  529     ui.listView->setFocus();
  530     item->setSelected(!item->isSelected());
  531     ui.listView->scrollToItem(item);
  532 
  533     QTextCursor tc(_editorP->textCursor());
  534     tc.setPosition(_positionList.at(id.toInt() - 1));
  535     _editorP->setTextCursor(tc);
  536     _editorP->verticalScrollBar()->setValue(_editorP->verticalScrollBar()->maximum());
  537     _editorP->ensureCursorVisible();
  538 }
  539 
  540 void c2bReferenceList::clearSelections()
  541 {
  542     disconnect(ui.listView, SIGNAL(itemSelectionChanged()), this, SLOT(itemSelectionChanged()));
  543     QTreeWidgetItemIterator it(ui.listView, QTreeWidgetItemIterator::Selected);
  544     while (*it)
  545     {
  546         (*it)->setSelected(false);
  547         ++it;
  548     }
  549     itemSelectionChanged();
  550     connect(ui.listView, SIGNAL(itemSelectionChanged()), this, SLOT(itemSelectionChanged()));
  551 }
  552 
  553 void c2bReferenceList::itemSelectionChanged()
  554 {
  555     int entries(0);
  556     int doi(0);
  557     int file(0);
  558     int url(0);
  559     int author(0);
  560     int title(0);
  561     QTreeWidgetItemIterator it(ui.listView, QTreeWidgetItemIterator::Selected | QTreeWidgetItemIterator::NotHidden);
  562     while (*it)
  563     {
  564         if (!_doiList.at((*it)->text(_id_index).toInt() - 1).isEmpty())
  565             ++doi;
  566         if (!_fileList.at((*it)->text(_id_index).toInt() - 1).isEmpty())
  567             ++file;
  568         if (!_urlList.at((*it)->text(_id_index).toInt() - 1).isEmpty())
  569             ++url;
  570         if (!(*it)->text(_author_index).isEmpty())
  571             ++author;
  572         if (!(*it)->text(_title_index).isEmpty())
  573             ++title;
  574         ++entries;
  575         ++it;
  576     }
  577     citeEntryAction->setEnabled(entries > 0);
  578     citeEntryAction->setStatusTip(tr("Cite selected entries. %1 Entries selected.").arg(entries));
  579     openDOIAction->setEnabled(doi > 0);
  580     openDOIAction->setStatusTip(tr("Browse reference by DOI. %1 DOIs in selected entries.").arg(doi));
  581     openFileAction->setEnabled(file > 0);
  582     openFileAction->setStatusTip(tr("Open document file. %1 Files in selected entries.").arg(file));
  583     openUrlAction->setEnabled(url > 0);
  584     openUrlAction->setStatusTip(tr("Open document URL. %1 URLs in selected entries.").arg(url));
  585     openAuthorsWebSearchAction->setEnabled(author > 0);
  586     openAuthorsWebSearchAction->setStatusTip(tr("Web search by Author. %1 Entries selected.").arg(author));
  587     openTitleWebSearchAction->setEnabled(title > 0);
  588     openTitleWebSearchAction->setStatusTip(tr("Web search by Title. %1 Entries selected.").arg(title));
  589     emit hasSelectedItems(entries > 0);
  590 }
  591 
  592 QStringList c2bReferenceList::selectedKeys() const
  593 {
  594     QStringList keys;
  595     QTreeWidgetItemIterator it(ui.listView, QTreeWidgetItemIterator::Selected | QTreeWidgetItemIterator::NotHidden);
  596     while (*it)
  597     {
  598         if (!(*it)->text(_key_index).isEmpty())
  599             keys.append((*it)->text(_key_index));
  600         ++it;
  601     }
  602     return keys;
  603 }
  604 
  605 void c2bReferenceList::setLyXPipe()
  606 {
  607     _citerP->setLyXPipe();
  608 }
  609 
  610 
  611 /***************************************************************************
  612     Filter Bar
  613  ***************************************************************************/
  614 
  615 void c2bReferenceList::setupFilterBar()
  616 {
  617     const QStringList types(searchPattern::types());
  618     _filter_mode = _settingsP->value("c2bReferenceList/FilterMode", types.first()).toString();
  619     QActionGroup* filterMode = new QActionGroup(this);
  620     filterMode->setExclusive(true);
  621     for (int i = 0; i < types.count(); ++i)
  622     {
  623         const QString& t = types.at(i);
  624         QAction* act = filterMode->addAction(t);
  625         act->setCheckable(true);
  626         if (_filter_mode == t)
  627             act->setChecked(true);
  628     }
  629     QMenu* filterModeM = new QMenu(this);
  630     filterModeM->addActions(filterMode->actions());
  631     ui.filterB->setMenu(filterModeM);
  632     connect(filterMode, SIGNAL(triggered(QAction*)), this, SLOT(setFilterMode(QAction*)));
  633     connect(ui.comboFilter, SIGNAL(editTextChanged(QString)), this, SLOT(blockFilterSignals()));
  634 }
  635 
  636 void c2bReferenceList::setFilterMode(QAction* mode)
  637 {
  638     _filter_mode = mode->text();
  639     _settingsP->setValue("c2bReferenceList/FilterMode", _filter_mode);
  640     filterList();
  641 }
  642 
  643 void c2bReferenceList::blockFilterSignals()
  644 {
  645     ui.comboFilter->blockSignals(true);
  646     QTimer::singleShot(500, this, SLOT(filterList()));
  647 }
  648 
  649 void c2bReferenceList::filterList()
  650 {
  651     const QString text(ui.comboFilter->currentText());
  652     if (text.isEmpty())
  653     {
  654         QTreeWidgetItemIterator it(ui.listView);
  655         while (*it)
  656         {
  657             (*it)->setHidden(false);
  658             ++it;
  659         }
  660     }
  661     else
  662     {
  663         searchPattern pattern(text, _filter_mode);
  664         QTreeWidgetItemIterator it(ui.listView);
  665         while (*it)
  666         {
  667             QTreeWidgetItem* item = *it;
  668             if (pattern.matches(item->text(_author_index)) || pattern.matches(item->text(_title_index)))
  669                 item->setHidden(false);
  670             else
  671                 item->setHidden(true);
  672             ++it;
  673         }
  674         QTimer::singleShot(5000, this, SLOT(keepFilterPattern()));
  675     }
  676     itemSelectionChanged();
  677     ui.comboFilter->blockSignals(false);
  678 }
  679 
  680 void c2bReferenceList::keepFilterPattern()
  681 {
  682     const QString text(ui.comboFilter->currentText());
  683     if (!text.isEmpty())
  684         if (ui.comboFilter->findText(text) < 0)
  685             ui.comboFilter->addItem(text);
  686 }