Package com.salas.bb.whatshot

Source Code of com.salas.bb.whatshot.ListModel$FilterListener

// BlogBridge -- RSS feed reader, manager, and web based service
// Copyright (C) 2002-2007 by R. Pito Salas
//
// 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., 59 Temple Place,
// Suite 330, Boston, MA 02111-1307 USA
//
// Contact: R. Pito Salas
// mailto:pitosalas@users.sourceforge.net
// More information: about BlogBridge
// http://www.blogbridge.com
// http://sourceforge.net/projects/blogbridge
//
// $Id: ListModel.java,v 1.15 2007/08/27 15:07:49 spyromus Exp $
//

package com.salas.bb.whatshot;

import com.jgoodies.binding.value.ValueModel;
import com.salas.bb.domain.IArticle;
import com.salas.bb.domain.IFeed;
import com.salas.bb.domain.IGuide;
import com.salas.bb.search.ResultsListModel;
import com.salas.bb.utils.StringUtils;
import com.salas.bb.utils.swingworker.SwingWorker;

import javax.swing.*;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.regex.Pattern;

/**
* The results list model.
*/
public class ListModel extends ResultsListModel implements ILinkResolverListener
{
    /** Minimum number of references in a group for the link to be hot. */
    private static final int MIN_REFS_IN_GROUP = 2;
    /** Maximum number of hot links to put in the model from the results. */
    private static final int MAX_HOT_LINKS = 20;

    /** Hotlink sequence number which is used to generate unique keys within the model. */
    private int hotlinkSeqNum;

    /** What's hot engine used to get the results. */
    private final Engine engine;

    /** Filter: minimum starz. '1' means no filtering. */
    private final ValueModel mdlStarz;
    /** Filter: unread only article allowed. */
    private final ValueModel mdlOnlyUnread;
    /** Filter: time options. */
    private final ValueModel mdlTimeOption;

    /** Resolves links into titles. */
    private final LinkResolver resolver;

    /** The list of all hotlinks in the model. */
    private List<Engine.HotLink> hotlinks = new ArrayList<Engine.HotLink>();

    /** The guide to look for hot links in. */
    private IGuide targetGuide;
    /** The ignore-pattern compiled from ignorePatterns or <code>NULL</code> if not set. */
    private Pattern ignorePattern;
    /** Don't count self references flag. */
    private boolean dontCountSelfReferences;
    /** Suppress single source links. */
    private boolean suppressSameSourceLinks;

    /**
     * Creates a list model for a given engine.
     *
     * @param engine            engine.
     * @param mdlStarz          starz filter model.
     * @param mdlOnlyUnread     unread only flag model.
     * @param mdlTimeOption     time options.
     */
    public ListModel(Engine engine, ValueModel mdlStarz, ValueModel mdlOnlyUnread, ValueModel mdlTimeOption)
    {
        this.engine = engine;
        this.mdlStarz = mdlStarz;
        this.mdlOnlyUnread = mdlOnlyUnread;
        this.mdlTimeOption = mdlTimeOption;

        resolver = new LinkResolver(this);
        FilterListener fl = new FilterListener();
        mdlStarz.addValueChangeListener(fl);
        mdlOnlyUnread.addValueChangeListener(fl);
        mdlTimeOption.addValueChangeListener(fl);
    }

    /**
     * Invoked when the group resolution is completed.
     *
     * @param group group resolved.
     */
    public void onGroupResolved(final HotResultGroup group)
    {
        SwingUtilities.invokeLater(new Runnable()
        {
            public void run()
            {
                fireGroupUpdated(group);
            }
        });
    }

    /**
     * Stops link resolution immediately.
     */
    public void stopLinkResolution()
    {
        if (resolver != null) resolver.stop();
    }

    /**
     * Start scanning and filling the model.
     *
     * @return returns the scanner to start.
     */
    public SwingWorker scan()
    {
        return new Scanner();
    }

    /**
     * Processes the links from the engine.
     *
     * @param links links to process.
     */
    void processLinks(List<Engine.HotLink> links)
    {
        for (Engine.HotLink hotLink : links)
        {
            // We don't need links with little references and
            // we allow only some given number of hotlinks
            if (hotLink.size() < MIN_REFS_IN_GROUP) break;

            hotlinks.add(hotLink);
        }

        review();
    }

    private void review()
    {
        List<HotResultItem> groupItems = new LinkedList<HotResultItem>();
        List<HotResultGroup> newGroups = new LinkedList<HotResultGroup>();
        for (Engine.HotLink link : hotlinks)
        {
            List<IArticle> matchingArticles = getMatchingArticles(link);
            if (matchingArticles == null) continue;

            String linkString = link.getLink().toString();
            groupItems.clear();

            for (IArticle article : matchingArticles)
            {
                groupItems.add(new HotResultItem(article, linkString));
            }

            if (groupItems.size() >= MIN_REFS_IN_GROUP)
            {
                HotResultGroup group = new HotResultGroup(hotlinkSeqNum++, link);
                for (HotResultItem item : groupItems) group.add(item);
                newGroups.add(group);
            }
        }

        // Sort groups by the number of items in them
        Collections.sort(newGroups);

        fireClear();
        int i = 0;
        for (HotResultGroup group : newGroups)
        {
            group.setVisible(true);

            // Start resolving the group title
            if (!group.isResolved())
            {
                String title = resolver.resolve(group);
                if (title != null) group.setResolvedTitle(title);
            }

            fireGroupAdded(group, true);

            // Fire all items
            for (HotResultItem item : group) fireItemAdded(item, group);

            i++;
            if (i > MAX_HOT_LINKS) break;
        }
    }

    private List<IArticle> getMatchingArticles(Engine.HotLink link)
    {
        List<IArticle> matches;

        // Check against ignore pattern
        if (ignorePattern != null &&
                ignorePattern.matcher(link.getLink().toString()).find()) return null;

        // Check if has links from one source only
        IFeed feed = null;
        matches = new LinkedList<IArticle>();
        boolean fine = !suppressSameSourceLinks;
        for (IArticle article : link)
        {
            if (!matches(link, article)) continue;
            matches.add(article);

            if (!fine)
            {
                if (feed == null) feed = article.getFeed(); else
                if (feed != article.getFeed()) fine = true;
            }
        }

        return !fine ? null : matches;
    }

    private boolean matches(Engine.HotLink link, IArticle article)
    {
        // Check the rating
        if ((Boolean)mdlOnlyUnread.getValue() && article.isRead()) return false;

        // Check the time
        TimeOption to = (TimeOption)mdlTimeOption.getValue();
        if (article.getPublicationDate().getTime() < System.currentTimeMillis() - to.getOffset()) return false;

        // Check the starz
        Integer starz = (Integer)mdlStarz.getValue();
        IFeed feed = article.getFeed();
        if (starz > 1 && feed.getRating() < starz) return false;

        // Check self-referencing
        if (dontCountSelfReferences)
        {
            String linkHost = link.getLink().getHost();
            URL articleLink = article.getLink();
            if (articleLink != null && articleLink.getHost().equalsIgnoreCase(linkHost)) return false;
        }

        // Check guides
        return targetGuide == null || targetGuide.getID() == -1 || feed.belongsTo(targetGuide);
    }

    /**
     * Sets advanced filtering setup.
     *
     * @param ignorePatterns            ignore patterns in textual form (one per line).
     * @param dontCountSelfReferences   <code>TRUE</code> to never count links to self.
     * @param suppressSameSourceLinks   <code>TRUE</code> to suppress hot links referenced only from one source.
     * @param targetGuide               target guide to look for hot articles in.
     */
    public void setSetup(String ignorePatterns, boolean dontCountSelfReferences,
                         boolean suppressSameSourceLinks, IGuide targetGuide)
    {
        ignorePattern = StringUtils.isEmpty(ignorePatterns)
            ? null
            : Pattern.compile(StringUtils.keywordsToPattern(ignorePatterns));

        this.dontCountSelfReferences = dontCountSelfReferences;
        this.suppressSameSourceLinks = suppressSameSourceLinks;
        this.targetGuide = targetGuide;

        review();
    }

    /**
     * Scanner worker.
     */
    private class Scanner extends SwingWorker<List<Engine.HotLink>, Integer>
        implements IProgressListener
    {
        /**
         * Invoked when background processing should start.
         *
         * @return the result.
         *
         * @throws Exception in case of any error.
         */
        protected List<Engine.HotLink> doInBackground() throws Exception
        {
            return engine.scan(this);
        }

        @Override
        protected void done()
        {
            List<Engine.HotLink> links;
            try
            {
                links = get();
            } catch (Exception e)
            {
                return;
            }

            processLinks(links);
        }

        /**
         * Invoked on progress change.
         *
         * @param percent percents [0 - 100];
         */
        public void onProgress(int percent)
        {
            setProgress(percent);
        }
    }

    private class FilterListener implements PropertyChangeListener
    {
        /**
         * Invoked when a filter property changes.
         *
         * @param evt event.
         */
        public void propertyChange(PropertyChangeEvent evt)
        {
            review();
        }
    }
}
TOP

Related Classes of com.salas.bb.whatshot.ListModel$FilterListener

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.