<commit_before>/*
    This file is part of Akregator.

    Copyright (C) 2007 <NAME> <<EMAIL>>

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.

    As a special exception, permission is given to link this program
    with any edition of Qt, and distribute the resulting executable,
    without including the source code for Qt in the source distribution.
*/
#include "articlemodel.h"

#include "article.h"
#include "articlematcher.h"
#include "akregatorconfig.h"
#include "treenode.h"
#include "feed.h"

#include <syndication/tools.h>

#include <QString>
#include <QVector>

#include <KLocale>

#include <cassert>
#include <cmath>

using namespace Akregator;

class ArticleModel::Private {
private:
    ArticleModel* const q;
public:
    Private( TreeNode* node_, ArticleModel* qq );
    Akregator::TreeNode* node;
    QList<Akregator::Article> articles;
    QVector<QString> titleCache;
    
    void nodeDestroyed();
    void articlesAdded( TreeNode*, const QList<Article>& );
    void articlesRemoved( TreeNode*, const QList<Article>& );
    void articlesUpdated( TreeNode*, const QList<Article>& );

};

ArticleModel::Private::Private( TreeNode* node_, ArticleModel* qq )
 : q( qq ), node( node_ )
{
    Q_ASSERT( node );
    articles = node->articles();
    titleCache.resize( articles.count() );
    for ( int i = 0; i < articles.count(); ++i )
        titleCache[i] = Syndication::htmlToPlainText( articles[i].title() );
    connect( node, SIGNAL( destroyed() ) , q, SLOT( nodeDestroyed() ) );
    connect( node, SIGNAL( signalArticlesAdded( Akregator::TreeNode*, QList<Akregator::Article> ) ), 
                          q, SLOT( articlesAdded( Akregator::TreeNode*, QList<Akregator::Article> ) ) );
    connect( node, SIGNAL( signalArticlesRemoved( Akregator::TreeNode*, QList<Akregator::Article> ) ), 
                           q, SLOT( articlesRemoved( Akregator::TreeNode*, QList<Akregator::Article> ) ) );
    connect( node, SIGNAL( signalArticlesUpdated( Akregator::TreeNode*, QList<Akregator::Article> ) ),
                           q, SLOT( articlesUpdated( Akregator::TreeNode*, QList<Akregator::Article> ) ) );

}

Akregator::ArticleModel::ArticleModel(TreeNode* node, QObject* parent) : QAbstractTableModel( parent ), d( new Private( node, this ) )
{
}

Akregator::ArticleModel::~ArticleModel()
{
    delete d;
}

int Akregator::ArticleModel::columnCount( const QModelIndex& parent ) const
{
    return parent.isValid() ? 0 : ColumnCount;
}

int Akregator::ArticleModel::rowCount( const QModelIndex& parent ) const
{
    return parent.isValid() ? 0 : d->articles.count();
}

QVariant Akregator::ArticleModel::headerData( int section, Qt::Orientation, int role ) const
{
    if ( role != Qt::DisplayRole )
        return QVariant();

    switch (section)
    {
        case ItemTitleColumn:
            return i18n("Title");
        case FeedTitleColumn:
            return i18n("Feed");
        case DateColumn:
            return i18n("Date");
        case AuthorColumn:
            return i18n("Author");
        case DescriptionColumn:
            return i18n("Description");
        case ContentColumn:
            return i18n("Content");
    }

    return QVariant();
}

QVariant Akregator::ArticleModel::data( const QModelIndex& index, int role ) const
{
    if ( !index.isValid() || index.row() < 0 || index.row() >= d->articles.count() )
        return QVariant();
    const int row = index.row();
    const Akregator::Article& article( d->articles[row] );

    if ( article.isNull() )
        return QVariant();

    switch ( role )
    {
        case Qt::DisplayRole:
        {
            switch ( index.column() )
            {
                case FeedTitleColumn:
                    return article.feed() ? article.feed()->title() : QVariant();
                case DateColumn:
                    return article.pubDate();
                case ItemTitleColumn:
                    return d->titleCache[row];
                case AuthorColumn:
                    return article.author();
                case DescriptionColumn:
                case ContentColumn:
                    return article.description();
            }
        }
        case LinkRole:
        {
            return article.link();<commit_msg>Use current locale settings when formatting the publishing date of an article for display in the article list, with fancy rendition of dates less than one week old (eg. "Today <time>", "Yesterday <time>")<commit_after>/*
    This file is part of Akregator.

    Copyright (C) 2007 <NAME> <<EMAIL>>

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.

    As a special exception, permission is given to link this program
    with any edition of Qt, and distribute the resulting executable,
    without including the source code for Qt in the source distribution.
*/
#include "articlemodel.h"

#include "article.h"
#include "articlematcher.h"
#include "akregatorconfig.h"
#include "treenode.h"
#include "feed.h"

#include <syndication/tools.h>

#include <QString>
#include <QVector>

#include <KLocale>
#include <KGlobal>

#include <cassert>
#include <cmath>

using namespace Akregator;

class ArticleModel::Private {
private:
    ArticleModel* const q;
public:
    Private( TreeNode* node_, ArticleModel* qq );
    Akregator::TreeNode* node;
    QList<Akregator::Article> articles;
    QVector<QString> titleCache;
    
    void nodeDestroyed();
    void articlesAdded( TreeNode*, const QList<Article>& );
    void articlesRemoved( TreeNode*, const QList<Article>& );
    void articlesUpdated( TreeNode*, const QList<Article>& );

};

ArticleModel::Private::Private( TreeNode* node_, ArticleModel* qq )
 : q( qq ), node( node_ )
{
    Q_ASSERT( node );
    articles = node->articles();
    titleCache.resize( articles.count() );
    for ( int i = 0; i < articles.count(); ++i )
        titleCache[i] = Syndication::htmlToPlainText( articles[i].title() );
    connect( node, SIGNAL( destroyed() ) , q, SLOT( nodeDestroyed() ) );
    connect( node, SIGNAL( signalArticlesAdded( Akregator::TreeNode*, QList<Akregator::Article> ) ), 
                          q, SLOT( articlesAdded( Akregator::TreeNode*, QList<Akregator::Article> ) ) );
    connect( node, SIGNAL( signalArticlesRemoved( Akregator::TreeNode*, QList<Akregator::Article> ) ), 
                           q, SLOT( articlesRemoved( Akregator::TreeNode*, QList<Akregator::Article> ) ) );
    connect( node, SIGNAL( signalArticlesUpdated( Akregator::TreeNode*, QList<Akregator::Article> ) ),
                           q, SLOT( articlesUpdated( Akregator::TreeNode*, QList<Akregator::Article> ) ) );

}

Akregator::ArticleModel::ArticleModel(TreeNode* node, QObject* parent) : QAbstractTableModel( parent ), d( new Private( node, this ) )
{
}

Akregator::ArticleModel::~ArticleModel()
{
    delete d;
}

int Akregator::ArticleModel::columnCount( const QModelIndex& parent ) const
{
    return parent.isValid() ? 0 : ColumnCount;
}

int Akregator::ArticleModel::rowCount( const QModelIndex& parent ) const
{
    return parent.isValid() ? 0 : d->articles.count();
}

QVariant Akregator::ArticleModel::headerData( int section, Qt::Orientation, int role ) const
{
    if ( role != Qt::DisplayRole )
        return QVariant();

    switch (section)
    {
        case ItemTitleColumn:
            return i18n("Title");
        case FeedTitleColumn:
            return i18n("Feed");
        case DateColumn:
            return i18n("Date");
        case AuthorColumn:
            return i18n("Author");
        case DescriptionColumn:
            return i18n("Description");
        case ContentColumn:
            return i18n("Content");
    }

    return QVariant();
}

QVariant Akregator::ArticleModel::data( const QModelIndex& index, int role ) const
{
    if ( !index.isValid() || index.row() < 0 || index.row() >= d->articles.count() )
        return QVariant();
    const int row = index.row();
    const Akregator::Article& article( d->articles[row] );

    if ( article.isNull() )
        return QVariant();

    switch ( role )
    {
        case Qt::DisplayRole:
        {
            switch ( index.column() )
            {
                case FeedTitleColumn:
                    return article.feed() ? article.feed()->title() : QVariant();
                case DateColumn:
                    return KGlobal::locale()->formatDateTime(article.pubDate(),
                                                             KLocale::FancyShortDate);
                case ItemTitleColumn:
                    return d->titleCache[row];
                case AuthorColumn:
                    return article.author();
                case DescriptionColumn:
                case ContentColumn:
                    return article.description();
            }
        }
        case LinkRole:
        {
            return article.link();
{'fraction_non_alphanumeric': 0.11036986166977338, 'fraction_numerical': 0.006278818797213774, 'mean_word_length': 2.7966480446927373, 'pattern_counts': {'":': 0, '<': 50, '<?xml version=': 0, '>': 61, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4867030', 'n_tokens_mistral': 2950, 'n_tokens_neox': 2780, 'n_words': 876}