"Fossies" - the Fresh Open Source Software Archive

Member "cb2bib-2.0.1/src/c2bCiterModel.cpp" (12 Feb 2021, 28458 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 "c2bCiterModel.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 "c2bCiterModel.h"
    8 
    9 #include <bibParser.h>
   10 
   11 #include "c2b.h"
   12 
   13 #include <QDateTime>
   14 #include <QIcon>
   15 
   16 namespace
   17 {
   18 
   19 template <typename T>
   20 class ascending
   21 {
   22 public:
   23     explicit ascending(const T& data) : _data(data) {}
   24     inline bool operator()(const int i, const int j)
   25     {
   26         return _data.at(i) < _data.at(j);
   27     }
   28 
   29 private:
   30     const T& _data;
   31 };
   32 
   33 } // namespace
   34 
   35 
   36 c2bCiterModel::c2bCiterModel(QObject* parento) : QAbstractTableModel(parento)
   37 {
   38     _first_column_color = QApplication::palette().color(QPalette::Active, QPalette::Base).darker(110);
   39     _clear();
   40 }
   41 
   42 
   43 void c2bCiterModel::loadCitations(const QStringList& fns)
   44 {
   45     emit layoutAboutToBeChanged();
   46     _clear();
   47     _analyzer.reload();
   48     for (int i = 0; i < fns.count(); ++i)
   49         _add_citations(fns.at(i));
   50     _set_table_data();
   51     _set_sort_indices();
   52     _update_format();
   53     emit layoutChanged();
   54     emit statusMessage(tr("Loaded %1 references from %2 files.").arg(_citation_count).arg(fns.count()));
   55 }
   56 
   57 void c2bCiterModel::loadCitations(const QString& fn)
   58 {
   59     emit layoutAboutToBeChanged();
   60     _clear();
   61     _analyzer.reload();
   62     _add_citations(fn);
   63     _set_table_data();
   64     _set_sort_indices();
   65     _update_format();
   66     emit layoutChanged();
   67     emit statusMessage(tr("Loaded %1 references.").arg(_citation_count));
   68 }
   69 
   70 void c2bCiterModel::reloadCitations(const QStringList& fns, const c2bCiter::State& state, QModelIndex* current_index)
   71 {
   72     emit layoutAboutToBeChanged();
   73     _clear();
   74     _analyzer.reload();
   75     for (int i = 0; i < fns.count(); ++i)
   76         _add_citations(fns.at(i));
   77     _set_table_data();
   78     _set_sort_indices();
   79     _update_format(state.format);
   80     const int current_item(_current_item(state.index_data));
   81     _update_current_index(current_item, current_index);
   82     _history.saveCurrentState(_format, _filter, current_item, current_index, _fstring);
   83     emit layoutChanged();
   84     emit statusMessage(tr("Loaded %1 references from %2 files.").arg(_citation_count).arg(fns.count()));
   85 }
   86 
   87 QVariant c2bCiterModel::data(const QModelIndex& i, int role) const
   88 {
   89     if (role == Qt::DisplayRole)
   90         return (this->*_display_ptr)(i.row(), i.column());
   91     else if (role == Qt::DecorationRole)
   92     {
   93         if (_format == c2bCiter::K && i.column() == 0)
   94             return QVariant(QIcon(":/icons/icons/bullet.png"));
   95         if (i.column() == 0)
   96         {
   97             if (_is_selected.at(_offset(i.row())))
   98                 return QVariant(QIcon(":/icons/icons/citer_citation_checked.png"));
   99             else
  100                 return QVariant(QIcon(":/icons/icons/citer_citation.png"));
  101         }
  102         return QVariant();
  103     }
  104     else if (role == Qt::BackgroundRole)
  105     {
  106         if (i.column() == 0 && _column_count > 1 && _format != c2bCiter::K)
  107             return _first_column_color;
  108         else
  109             return QVariant();
  110     }
  111     else
  112         return QVariant();
  113 }
  114 
  115 QStringList c2bCiterModel::dataSelectedCiteIds() const
  116 {
  117     QStringList ids;
  118     for (int i = 0; i < _citation_count; ++i)
  119         if (_is_selected.at(_map_yajt.at(i)))
  120             ids.append(_citeId.at(_map_yajt.at(i)));
  121     return ids;
  122 }
  123 
  124 void c2bCiterModel::setPatternFilter(const QString& pattern, QModelIndex* current_index, const c2bCiter::Format format)
  125 {
  126     _history.saveCurrentState(_format, _filter, _current_item(current_index), current_index, _fstring);
  127     emit layoutAboutToBeChanged();
  128     const QStringList word(pattern.split(c2bUtils::nonLetter, QString::SkipEmptyParts));
  129     _filter = word.count() > 0 ? c2bCiter::Pattern : c2bCiter::None;
  130     _format = format;
  131     if (_filter == c2bCiter::Pattern)
  132     {
  133         _fstring = pattern;
  134         if (_format == c2bCiter::K)
  135         {
  136             int j(0);
  137             for (int i = 0; i < _keyword_count; ++i)
  138             {
  139                 const QString& str = _analyzer.sentence(i);
  140                 bool mf(true);
  141                 for (int w = 0; w < word.count(); ++w)
  142                     if (!str.contains(word.at(w), Qt::CaseSensitive))
  143                     {
  144                         mf = false;
  145                         break;
  146                     }
  147                 if (mf)
  148                     _map_filter[j++] = i;
  149             }
  150             _row_count = j;
  151         }
  152         else
  153         {
  154             for (int i = 0; i < _citation_count; ++i)
  155             {
  156                 _matches_filter[i] = true;
  157                 const QString& str = _search_string.at(i);
  158                 for (int w = 0; w < word.count(); ++w)
  159                     if (!str.contains(word.at(w), Qt::CaseSensitive))
  160                     {
  161                         _matches_filter[i] = false;
  162                         break;
  163                     }
  164             }
  165         }
  166     }
  167     else
  168         _fstring.clear();
  169     _update_format(_format == c2bCiter::R ? _history.lastCitationFormat() : _format);
  170     _update_current_index(_format == c2bCiter::K ? _history.lastKeyword() : _history.lastCitation(), current_index);
  171     emit layoutChanged();
  172 }
  173 
  174 void c2bCiterModel::setSelectedFilter(QModelIndex* current_index)
  175 {
  176     emit statusLabel(tr("Selected"));
  177     _history.saveCurrentState(_format, _filter, _current_item(current_index), current_index, _fstring);
  178     emit layoutAboutToBeChanged();
  179     for (int i = 0; i < _citation_count; ++i)
  180         _matches_filter[i] = _is_selected.at(i);
  181     _filter = c2bCiter::Selected;
  182     _fstring.clear();
  183     _update_format(_history.lastCitationFormat());
  184     _update_current_index(_history.lastSelectionCitation(), current_index);
  185     emit layoutChanged();
  186 }
  187 
  188 void c2bCiterModel::setRelatedFilter(const QString& documentfn, QModelIndex* current_index,
  189                                      const c2bCiter::Format format)
  190 {
  191     _analyzer.setSimilarDocuments(documentfn);
  192     if (_analyzer.similarCount() == 0)
  193     {
  194         emit statusMessage(tr("No related references."));
  195         return;
  196     }
  197     emit statusLabel(tr("Related to '%1'").arg(_title.at(_file.value(documentfn))));
  198     _history.saveCurrentState(_format, _filter, _current_item(current_index), current_index, _fstring);
  199     emit layoutAboutToBeChanged();
  200     for (int i = 0; i < _citation_count; ++i)
  201         _matches_filter[i] = false;
  202     const int sc(_analyzer.similarCount());
  203     _related_count = 0;
  204     for (int i = 0; i < sc; ++i)
  205     {
  206         // Note that data in collectionAnalyzer index might not match
  207         // BibTeX files data (outdated index or users browsing
  208         // particular BibTeX file sets). Use full path document
  209         // filenames to set a mapping.
  210         const int j(_file.value(_analyzer.similar(i), -1));
  211         if (j == -1)
  212         {
  213             _analyzer.skipSimilarDocument(i);
  214             continue;
  215         }
  216         _matches_filter[j] = true;
  217         _map_filter[i] = j;
  218         ++_related_count;
  219     }
  220     _filter = c2bCiter::Related;
  221     _fstring = documentfn;
  222     _update_format(format);
  223     _update_current_index(_history.lastCitation(), current_index);
  224     emit layoutChanged();
  225 }
  226 
  227 void c2bCiterModel::setKeywordFilter(const QString& keyword, QModelIndex* current_index)
  228 {
  229     _analyzer.setKeywordDocuments(keyword);
  230     if (_analyzer.documentCount() == 0)
  231     {
  232         emit statusMessage(tr("No related references."));
  233         return;
  234     }
  235     emit statusLabel(tr("Related to '%1'").arg(keyword));
  236     _history.saveCurrentState(_format, _filter, _current_item(current_index), current_index, _fstring);
  237     emit layoutAboutToBeChanged();
  238     for (int i = 0; i < _citation_count; ++i)
  239         _matches_filter[i] = false;
  240     const int dc(_analyzer.documentCount());
  241     for (int i = 0; i < dc; ++i)
  242     {
  243         // See comment at c2bCiterModel::setRelatedFilter
  244         const int j(_file.value(_analyzer.document(i), -1));
  245         if (j == -1)
  246             continue;
  247         _matches_filter[j] = true;
  248     }
  249     _filter = c2bCiter::Keyword;
  250     _fstring = keyword;
  251     _update_format(_history.lastCitationFormat());
  252     _update_current_index(_history.lastKeyword(), current_index);
  253     emit layoutChanged();
  254 }
  255 
  256 void c2bCiterModel::setDocumentFilter(const QString& documentfn, QModelIndex* current_index)
  257 {
  258     _analyzer.setDocumentKeywords(documentfn);
  259     const int nk(_analyzer.keywordCount());
  260     if (nk == 0)
  261     {
  262         emit statusMessage(tr("No keywords from this reference."));
  263         return;
  264     }
  265     emit statusLabel(tr("Keywords from '%1'").arg(_title.at(_file.value(documentfn))));
  266     _history.saveCurrentState(_format, _filter, _current_item(current_index), current_index, _fstring);
  267     emit layoutAboutToBeChanged();
  268     int j(0);
  269     for (int i = 0; i < nk; ++i)
  270         _map_filter[j++] = _analyzer.keywordid(i);
  271     _row_count = j;
  272     _filter = c2bCiter::Document;
  273     _fstring = documentfn;
  274     _update_format(c2bCiter::K);
  275     _update_current_index(_history.lastKeyword(), current_index);
  276     emit layoutChanged();
  277 }
  278 
  279 void c2bCiterModel::setGlossaryView(QModelIndex* current_index)
  280 {
  281     _history.saveCurrentState(_format, _filter, _current_item(current_index), current_index, _fstring);
  282     emit layoutAboutToBeChanged();
  283     _filter = c2bCiter::None;
  284     _fstring.clear();
  285     _update_format(c2bCiter::K);
  286     _update_current_index(_history.lastKeyword(), current_index);
  287     emit patternFilterChanged(_fstring);
  288     emit layoutChanged();
  289 }
  290 
  291 void c2bCiterModel::selectCitation(const QModelIndex& i)
  292 {
  293     if (_format == c2bCiter::K)
  294         return;
  295     _is_selected[_offset(i.row())] = !_is_selected.at(_offset(i.row()));
  296     emit layoutChanged();
  297 }
  298 
  299 QList<int> c2bCiterModel::sizeHintForColumns() const
  300 {
  301     QList<int> sizes;
  302     switch (_format)
  303     {
  304     case c2bCiter::AJYT:
  305         sizes.append(std::min(20, _author_max_length + 2));
  306         sizes.append(20);
  307         sizes.append(6);
  308         sizes.append(100);
  309         break;
  310     case c2bCiter::IT:
  311         sizes.append(12);
  312         sizes.append(100);
  313         break;
  314     case c2bCiter::JYA:
  315         sizes.append(std::min(25, _journal_max_length));
  316         sizes.append(6);
  317         sizes.append(100);
  318         break;
  319     case c2bCiter::K:
  320         sizes.append(100);
  321         break;
  322     case c2bCiter::R:
  323         sizes.append(9);
  324         sizes.append(100);
  325         break;
  326     case c2bCiter::T:
  327         sizes.append(100);
  328         break;
  329     case c2bCiter::YAJT:
  330     default:
  331         sizes.append(8);
  332         sizes.append(75);
  333         sizes.append(25);
  334         sizes.append(100);
  335         break;
  336     }
  337     return sizes;
  338 }
  339 
  340 void c2bCiterModel::clearSelection()
  341 {
  342     emit layoutAboutToBeChanged();
  343     for (int i = 0; i < _citation_count; ++i)
  344         _is_selected[i] = false;
  345     emit layoutChanged();
  346 }
  347 
  348 void c2bCiterModel::clearCurrentFilter(QModelIndex* current_index)
  349 {
  350     if (_filter == c2bCiter::None)
  351         return;
  352     if (_filter != c2bCiter::Pattern && _history.lastState().filter == c2bCiter::Pattern)
  353     {
  354         const c2bCiter::State& s(_history.lastState());
  355         setPatternFilter(s.filter_string, current_index, s.format);
  356         emit patternFilterChanged(s.filter_string);
  357     }
  358     else
  359     {
  360         _history.saveCurrentState(_format, _filter, _current_item(current_index), current_index, _fstring);
  361         emit layoutAboutToBeChanged();
  362         _filter = c2bCiter::None;
  363         _fstring.clear();
  364         _update_format(_format == c2bCiter::R ? _history.lastCitationFormat() : _format);
  365         _update_current_index(_format == c2bCiter::K ? _history.lastKeyword() : _history.lastCitation(), current_index);
  366         emit patternFilterChanged(_fstring);
  367         emit layoutChanged();
  368     }
  369 }
  370 
  371 c2bCiter::State c2bCiterModel::currentState(const QModelIndex& current_index) const
  372 {
  373     const int current_item(_current_item(current_index));
  374     c2bCiter::State s(_format == c2bCiter::R ? _history.lastCitationFormat() : _format, _filter, current_index.row(),
  375                       _fstring);
  376     if (current_item > -1)
  377         s.index_data = (_format == c2bCiter::K) ? _analyzer.sentence(current_item) : _search_string.at(current_item);
  378     return s;
  379 }
  380 
  381 void c2bCiterModel::restoreState(const c2bCiter::State& s, QModelIndex* current_index)
  382 {
  383     if (current_index)
  384         _history.saveCurrentItemIndex(_format, _filter, _current_item(current_index));
  385     switch (s.filter)
  386     {
  387     case c2bCiter::None:
  388         emit layoutAboutToBeChanged();
  389         _filter = c2bCiter::None;
  390         _fstring.clear();
  391         _update_format(s.format);
  392         emit patternFilterChanged(_fstring);
  393         emit layoutChanged();
  394         break;
  395     case c2bCiter::Document:
  396         if (_file.contains(s.filter_string))
  397             emit statusLabel(tr("Keywords from '%1'").arg(_title.at(_file.value(s.filter_string))));
  398         setDocumentFilter(s.filter_string, 0);
  399         break;
  400     case c2bCiter::Keyword:
  401         setKeywordFilter(s.filter_string, 0);
  402         break;
  403     case c2bCiter::Pattern:
  404         setPatternFilter(s.filter_string, 0, s.format);
  405         emit patternFilterChanged(s.filter_string);
  406         break;
  407     case c2bCiter::Related:
  408         setRelatedFilter(s.filter_string, 0, s.format);
  409         break;
  410     case c2bCiter::Selected:
  411         emit statusLabel(tr("Selected"));
  412         setSelectedFilter(0);
  413         break;
  414     default:
  415         break;
  416     }
  417     if (current_index)
  418         *current_index = index(s.viewer_index, 0);
  419 }
  420 
  421 void c2bCiterModel::restorePreviousState(QModelIndex* current_index)
  422 {
  423     if (_history.currentState() == -1)
  424         _history.saveCurrentState(_format, _filter, _current_item(current_index), current_index, _fstring);
  425     const c2bCiter::State& s(_history.previousState());
  426     restoreState(s, 0);
  427     if (current_index)
  428         *current_index = index(s.viewer_index, 0);
  429 }
  430 
  431 void c2bCiterModel::restoreNextState(QModelIndex* current_index)
  432 {
  433     if (_history.currentState() == -1)
  434         return;
  435     const c2bCiter::State& s(_history.nextState());
  436     restoreState(s, 0);
  437     if (current_index)
  438         *current_index = index(s.viewer_index, 0);
  439 }
  440 
  441 void c2bCiterModel::updateFormat(const c2bCiter::Format format, QModelIndex* current_index)
  442 {
  443     if (_format == c2bCiter::K)
  444     {
  445         c2bCiter::State s(_history.lastNonKeywordState());
  446         s.format = format;
  447         restoreState(s, current_index);
  448     }
  449     else
  450     {
  451         emit layoutAboutToBeChanged();
  452         const int current_item(_current_item(current_index));
  453         _update_format(format);
  454         _update_current_index(current_item, current_index);
  455         emit layoutChanged();
  456     }
  457 }
  458 
  459 void c2bCiterModel::_update_format(const c2bCiter::Format format)
  460 {
  461     _format = format;
  462     _history.saveCurrentCitationFormat(_format);
  463     switch (_format)
  464     {
  465     case c2bCiter::AJYT:
  466         _column_count = 4;
  467         _display_ptr = &c2bCiterModel::_display_ajyt;
  468         break;
  469     case c2bCiter::IT:
  470         _column_count = 2;
  471         _display_ptr = &c2bCiterModel::_display_it;
  472         break;
  473     case c2bCiter::JYA:
  474         _column_count = 3;
  475         _display_ptr = &c2bCiterModel::_display_jya;
  476         break;
  477     case c2bCiter::K:
  478         _column_count = 1;
  479         _display_ptr = &c2bCiterModel::_display_k;
  480         break;
  481     case c2bCiter::R:
  482         _column_count = 2;
  483         _display_ptr = &c2bCiterModel::_display_r;
  484         break;
  485     case c2bCiter::T:
  486         _column_count = 1;
  487         _display_ptr = &c2bCiterModel::_display_t;
  488         break;
  489     case c2bCiter::YAJT:
  490     default:
  491         _column_count = 4;
  492         _display_ptr = &c2bCiterModel::_display_yajt;
  493         break;
  494     }
  495     _set_mapping();
  496 }
  497 
  498 int c2bCiterModel::_current_item(const QString& index_data) const
  499 {
  500     int current_item(-1);
  501     if (!index_data.isEmpty())
  502     {
  503         if (_format == c2bCiter::K)
  504         {
  505             for (int i = 0; i < _keyword_count; ++i)
  506                 if (index_data == _analyzer.sentence(i))
  507                 {
  508                     current_item = i;
  509                     break;
  510                 }
  511         }
  512         else
  513         {
  514             for (int i = 0; i < _citation_count; ++i)
  515                 if (index_data == _search_string.at(i))
  516                 {
  517                     current_item = i;
  518                     break;
  519                 }
  520         }
  521     }
  522     return current_item;
  523 }
  524 
  525 void c2bCiterModel::_update_current_index(const int current_item, QModelIndex* current_index) const
  526 {
  527     if (!current_index)
  528         return;
  529     if (current_item >= 0)
  530         for (int i = 0; i < _row_count; ++i)
  531             if (_offset(i) == current_item)
  532             {
  533                 *current_index = index(i, 0);
  534                 return;
  535             }
  536     *current_index = index(0, 0);
  537 }
  538 
  539 void c2bCiterModel::_add_citations(const QString& fn)
  540 {
  541     bibParser* bpP = c2b::bibParser();
  542     const QString tag_author("author");
  543     const QString tag_booktitle("booktitle");
  544     const QString tag_doi("doi");
  545     const QString tag_editor("editor");
  546     const QString tag_file("file");
  547     const QString tag_journal("journal");
  548     const QString tag_title("title");
  549     const QString tag_url("url");
  550     const QString tag_year("year");
  551     const QString template_position("%1:%2");
  552     QStringList fields;
  553     fields.append(tag_author);
  554     fields.append(tag_booktitle);
  555     fields.append(tag_doi);
  556     fields.append(tag_editor);
  557     fields.append(tag_file);
  558     fields.append(tag_journal);
  559     fields.append(tag_title);
  560     fields.append(tag_url);
  561     fields.append(tag_year);
  562     bibReference ref;
  563     bpP->initReferenceParsing(fn, fields, &ref);
  564     const QRegExp initials1("\\b\\w\\b");
  565     const QRegExp initials2("[^\\w\\s]");
  566     const QString bibtex(c2bUtils::fileToString(fn));
  567 
  568     while (bpP->referencesIn(bibtex, &ref))
  569     {
  570         QString author(ref.anyAuthor());
  571         if (!author.isEmpty())
  572         {
  573             author = bpP->authorFromBibTeX(author);
  574             author.remove(initials1);
  575             author.remove(initials2);
  576             author.replace(" and ", ", ");
  577             c2bUtils::simplifyString(author);
  578         }
  579 
  580         QString title(ref.anyTitle());
  581         c2bUtils::cleanTitle(title, true);
  582 
  583         QString url(ref.value(tag_url));
  584         if (url.isEmpty())
  585         {
  586             const QString doi(ref.value(tag_doi));
  587             if (!doi.isEmpty())
  588             {
  589                 if (doi.startsWith("http"))
  590                     url = QUrl::toPercentEncoding(doi);
  591                 else
  592                     url = "https://dx.doi.org/" + QUrl::toPercentEncoding(doi);
  593             }
  594         }
  595 
  596         QString file(ref.value(tag_file));
  597         if (!file.isEmpty())
  598             file = QDir::cleanPath(file);
  599 
  600         uint included_date;
  601         const QFileInfo finf(file);
  602         if (finf.exists())
  603             included_date = QDateTime(finf.lastModified().date()).toTime_t();
  604         else
  605             included_date = 0;
  606 
  607         _author_string.append(author);
  608         _bibtex_position.append(template_position.arg(fn).arg(ref.positionValue));
  609         _citeId.append(ref.citeidName);
  610         _included_date.append(included_date);
  611         _journal.append(ref.anyJournal());
  612         _title.append(title);
  613         _url.append(url);
  614         _year.append(ref.value(tag_year));
  615         if (!file.isEmpty())
  616             _file.insert(file, _citation_count);
  617 
  618         _citation_count++;
  619     }
  620 }
  621 
  622 void c2bCiterModel::_clear()
  623 {
  624     _filter = c2bCiter::None;
  625     _format = c2bCiter::AJYT;
  626 
  627     _author.clear();
  628     _author_string.clear();
  629     _bibtex_position.clear();
  630     _citeId.clear();
  631     _file.clear();
  632     _fstring.clear();
  633     _history.clear();
  634     _included_date.clear();
  635     _is_selected.clear();
  636     _journal.clear();
  637     _map_ajyt.clear();
  638     _map_author.clear();
  639     _map_filter.clear();
  640     _map_it.clear();
  641     _map_jya.clear();
  642     _map_t.clear();
  643     _map_yajt.clear();
  644     _matches_filter.clear();
  645     _search_string.clear();
  646     _title.clear();
  647     _url.clear();
  648     _year.clear();
  649 
  650     _author_count = 0;
  651     _author_max_length = 0;
  652     _citation_count = 0;
  653     _column_count = 0;
  654     _journal_max_length = 0;
  655     _keyword_count = 0;
  656     _mapping = 0;
  657     _related_count = 0;
  658     _row_count = 0;
  659 }
  660 
  661 
  662 /****************************************************************************
  663 
  664   SETTING DATA POINTERS
  665 
  666 *****************************************************************************/
  667 
  668 void c2bCiterModel::_set_table_data()
  669 {
  670     const QString sep(", ");
  671     const QChar dot('.');
  672     for (int i = 0; i < _citation_count; ++i)
  673         _author_count += _author_string.at(i).count(sep) + 1;
  674     _author.resize(_author_count);
  675     _map_author.resize(_author_count);
  676     int ij(0);
  677     for (int i = 0; i < _citation_count; ++i)
  678     {
  679         const QStringList authors(_author_string.at(i).split(sep, QString::KeepEmptyParts));
  680         for (int j = 0; j < authors.count(); ++j)
  681         {
  682             _author[ij] = authors.at(j).trimmed();
  683             _map_author[ij] = i;
  684             _author_max_length = std::max(_author_max_length, _author.at(ij).length());
  685             ++ij;
  686         }
  687     }
  688     if (_author_count != ij)
  689         qFatal("c2bCiterModel::_set_table_data: Mismatch author mapping");
  690 
  691     bibParser* bpP = c2b::bibParser();
  692     for (int i = 0; i < _citation_count; ++i)
  693     {
  694         _journal[i] = bpP->abbreviatedJournal(_journal.at(i));
  695         _journal[i].remove(dot);
  696         _journal_max_length = std::max(_journal_max_length, _journal.at(i).length());
  697     }
  698 
  699     _is_selected.resize(_citation_count);
  700     for (int i = 0; i < _citation_count; ++i)
  701         _is_selected[i] = false;
  702 
  703     _keyword_count = _analyzer.sentenceCount();
  704     const int mca(std::max(_citation_count, _author_count));
  705     const int mcas(std::max(mca, _keyword_count));
  706     _matches_filter.resize(mca);
  707     _map_filter.resize(mcas);
  708 }
  709 
  710 void c2bCiterModel::_set_sort_indices()
  711 {
  712     const QChar sp(' ');
  713 
  714     // AJYT
  715     // Use _search_string as temporary for sorting
  716     _search_string.resize(_author_count);
  717     for (int i = 0; i < _author_count; ++i)
  718     {
  719         const int j(_map_author.at(i));
  720         _search_string[i] = c2bUtils::toAscii(
  721                                 _author.at(i) + sp + _journal.at(j) + sp + _year.at(j) + sp + _title.at(j), c2bUtils::Collation);
  722     }
  723     _map_ajyt.resize(_author_count);
  724     for (int i = 0; i < _author_count; ++i)
  725         _map_ajyt[i] = i;
  726     ascending<QVector<QString>> ajyt(_search_string);
  727     std::sort(_map_ajyt.begin(), _map_ajyt.end(), ajyt);
  728 
  729     // IT
  730     _search_string.resize(_citation_count);
  731     const int current_dtt(QDateTime::currentDateTime().toTime_t());
  732     const QString dtt("%1");
  733     const QChar padding('0');
  734     for (int i = 0; i < _citation_count; ++i)
  735         _search_string[i] = c2bUtils::toAscii(
  736                                 dtt.arg(current_dtt - _included_date.at(i), 10, 10, padding) + sp + _title.at(i), c2bUtils::Collation);
  737     _map_it.resize(_citation_count);
  738     for (int i = 0; i < _citation_count; ++i)
  739         _map_it[i] = i;
  740     ascending<QVector<QString>> it(_search_string);
  741     std::sort(_map_it.begin(), _map_it.end(), it);
  742 
  743     // JYA
  744     for (int i = 0; i < _citation_count; ++i)
  745         _search_string[i] =
  746             c2bUtils::toAscii(_journal.at(i) + sp + _year.at(i) + sp + _author_string.at(i), c2bUtils::Collation);
  747     _map_jya.resize(_citation_count);
  748     for (int i = 0; i < _citation_count; ++i)
  749         _map_jya[i] = i;
  750     ascending<QVector<QString>> jya(_search_string);
  751     std::sort(_map_jya.begin(), _map_jya.end(), jya);
  752 
  753     // T
  754     for (int i = 0; i < _citation_count; ++i)
  755         _search_string[i] = c2bUtils::toAscii(_title.at(i), c2bUtils::Collation);
  756     _map_t.resize(_citation_count);
  757     for (int i = 0; i < _citation_count; ++i)
  758         _map_t[i] = i;
  759     ascending<QVector<QString>> t(_search_string);
  760     std::sort(_map_t.begin(), _map_t.end(), t);
  761 
  762     // YAJT
  763     for (int i = 0; i < _citation_count; ++i)
  764         _search_string[i] = c2bUtils::toAscii(
  765                                 _year.at(i) + sp + _author_string.at(i) + sp + _journal.at(i) + sp + _title.at(i), c2bUtils::Collation);
  766     _map_yajt.resize(_citation_count);
  767     for (int i = 0; i < _citation_count; ++i)
  768         _map_yajt[i] = i;
  769     ascending<QVector<QString>> yajt(_search_string);
  770     std::sort(_map_yajt.begin(), _map_yajt.end(), yajt);
  771     // Keep _search_string for filtering
  772 }
  773 
  774 void c2bCiterModel::_set_mapping()
  775 {
  776     switch (_format)
  777     {
  778     case c2bCiter::AJYT:
  779         _row_count = _author_count;
  780         _mapping = &_map_ajyt;
  781         break;
  782     case c2bCiter::IT:
  783         _row_count = _citation_count;
  784         _mapping = &_map_it;
  785         break;
  786     case c2bCiter::JYA:
  787         _row_count = _citation_count;
  788         _mapping = &_map_jya;
  789         break;
  790     case c2bCiter::K:
  791         _row_count = _filter == c2bCiter::None ? _keyword_count : _row_count;
  792         break;
  793     case c2bCiter::R:
  794         _row_count = _related_count;
  795         _mapping = &_map_filter;
  796         break;
  797     case c2bCiter::T:
  798         _row_count = _citation_count;
  799         _mapping = &_map_t;
  800         break;
  801     case c2bCiter::YAJT:
  802     default:
  803         _row_count = _citation_count;
  804         _mapping = &_map_yajt;
  805         break;
  806     }
  807 
  808     if (_filter == c2bCiter::None)
  809         return;
  810     if (_format == c2bCiter::K)
  811     {
  812         _mapping = &_map_filter;
  813         return;
  814     }
  815     if (_format == c2bCiter::R) // _map_filter is already set in setRelatedFilter
  816         return;
  817 
  818     int r(0);
  819     if (_format == c2bCiter::AJYT)
  820     {
  821         for (int i = 0; i < _row_count; ++i)
  822             if (_matches_filter.at(_map_author.at(_mapping->at(i))))
  823                 _map_filter[r++] = _mapping->at(i);
  824     }
  825     else
  826     {
  827         for (int i = 0; i < _row_count; ++i)
  828             if (_matches_filter.at(_mapping->at(i)))
  829                 _map_filter[r++] = _mapping->at(i);
  830     }
  831     _row_count = r;
  832     _mapping = &_map_filter;
  833 }
  834 
  835 QString c2bCiterModel::_display_ajyt(const int row, const int column) const
  836 {
  837     switch (column)
  838     {
  839     case 0:
  840         return _author.at(_mapping->at(row));
  841     case 1:
  842         return _journal.at(_map_author.at(_mapping->at(row)));
  843     case 2:
  844         return _year.at(_map_author.at(_mapping->at(row)));
  845     case 3:
  846         return _title.at(_map_author.at(_mapping->at(row)));
  847     default:
  848         return QString();
  849     }
  850 }
  851 
  852 QString c2bCiterModel::_display_it(const int row, const int column) const
  853 {
  854     switch (column)
  855     {
  856     case 0:
  857         return _included_date.at(_offset(row)) > 0
  858                ? QDateTime::fromTime_t(_included_date.at(_offset(row))).date().toString(Qt::ISODate)
  859                : QString();
  860     case 1:
  861         return _title.at(_offset(row));
  862     default:
  863         return QString();
  864     }
  865 }
  866 
  867 QString c2bCiterModel::_display_jya(const int row, const int column) const
  868 {
  869     switch (column)
  870     {
  871     case 0:
  872         return _journal.at(_offset(row));
  873     case 1:
  874         return _year.at(_offset(row));
  875     case 2:
  876         return _author_string.at(_offset(row));
  877     default:
  878         return QString();
  879     }
  880 }
  881 
  882 QString c2bCiterModel::_display_k(const int row, const int column) const
  883 {
  884     switch (column)
  885     {
  886     case 0:
  887         return _analyzer.sentence(_offset(row));
  888     default:
  889         return QString();
  890     }
  891 }
  892 
  893 QString c2bCiterModel::_display_r(const int row, const int column) const
  894 {
  895     switch (column)
  896     {
  897     case 0:
  898         return QString("%1%").arg(100 * _analyzer.similarity(row), 3, 'f', 0);
  899     case 1:
  900         return _title.at(_offset(row));
  901     default:
  902         return QString();
  903     }
  904 }
  905 
  906 QString c2bCiterModel::_display_t(const int row, const int column) const
  907 {
  908     switch (column)
  909     {
  910     case 0:
  911         return _title.at(_offset(row));
  912     default:
  913         return QString();
  914     }
  915 }
  916 
  917 QString c2bCiterModel::_display_yajt(const int row, const int column) const
  918 {
  919     switch (column)
  920     {
  921     case 0:
  922         return _year.at(_offset(row));
  923     case 1:
  924         return _author_string.at(_offset(row));
  925     case 2:
  926         return _journal.at(_offset(row));
  927     case 3:
  928         return _title.at(_offset(row));
  929     default:
  930         return QString();
  931     }
  932 }
  933 
  934 int c2bCiterModel::_offset(const int i) const
  935 {
  936     if (_format == c2bCiter::AJYT)
  937         return _map_author.at(_mapping->at(i));
  938     else if (_format == c2bCiter::K && _filter == c2bCiter::None)
  939         return i;
  940     else
  941         return _mapping->at(i);
  942 }