Package org.rssowl.ui.internal.views.explorer

Source Code of org.rssowl.ui.internal.views.explorer.BookMarkFilter

/*   **********************************************************************  **
**   Copyright notice                                                       **
**                                                                          **
**   (c) 2005-2006 RSSOwl Development Team                                  **
**   http://www.rssowl.org/                                                 **
**                                                                          **
**   All rights reserved                                                    **
**                                                                          **
**   This program and the accompanying materials are made available under   **
**   the terms of the Eclipse Public License v1.0 which accompanies this    **
**   distribution, and is available at:                                     **
**   http://www.rssowl.org/legal/epl-v10.html                               **
**                                                                          **
**   A copy is found in the file epl-v10.html and important notices to the  **
**   license from the team is found in the textfile LICENSE.txt distributed **
**   in this package.                                                       **
**                                                                          **
**   This copyright notice MUST APPEAR in all copies of the file!           **
**                                                                          **
**   Contributors:                                                          **
**     RSSOwl Development Team - initial API and implementation             **
**                                                                          **
**  **********************************************************************  */

package org.rssowl.ui.internal.views.explorer;

import org.eclipse.jface.viewers.AbstractTreeViewer;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerFilter;
import org.rssowl.core.persist.IBookMark;
import org.rssowl.core.persist.IEntity;
import org.rssowl.core.persist.IMark;
import org.rssowl.core.persist.INews;
import org.rssowl.core.persist.ISearchMark;
import org.rssowl.core.persist.event.ModelEvent;
import org.rssowl.core.persist.reference.FeedLinkReference;
import org.rssowl.ui.internal.Controller;
import org.rssowl.ui.internal.NewsService;
import org.rssowl.ui.internal.util.ModelUtils;
import org.rssowl.ui.internal.util.StringMatcher;

import java.text.BreakIterator;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.List;
import java.util.Set;

/**
* Filter matching the leaf-nodes of a Tree-Structure. Parent Nodes are made
* visible as soon as leaf-nodes match the filter. This causes the entire tree
* structure to be realized.
* <p>
* Note: Inline StringMatcher from 3.2 final as it is internal API.
* </p>
*
* @author bpasero
*/
public class BookMarkFilter extends ViewerFilter {

  /** Possible Filter Values */
  public enum Type {

    /** Show all Feeds */
    SHOW_ALL,

    /** Show Feeds with new News */
    SHOW_NEW,

    /** Show Feeds with unread News */
    SHOW_UNREAD,

    /** Show Feeds that had an error while loading */
    SHOW_ERRONEOUS,

    /** Show never visited Feeds */
    SHOW_NEVER_VISITED,

    /** Show sticky Feeds */
    SHOW_STICKY
  }

  /** Possible Search Targets */
  public enum SearchTarget {

    /** Search Name */
    NAME,

    /** Search Link */
    LINK,
  }

  /* The string pattern matcher used for this pattern filter */
  private StringMatcher fMatcher;

  /* Current Filter Value */
  private Type fType = Type.SHOW_ALL;

  /* Current Search Target */
  private SearchTarget fSearchTarget = SearchTarget.NAME;

  /* News-Service */
  private NewsService fNewsService = Controller.getDefault().getNewsService();

  /*
   * @see org.eclipse.jface.viewers.ViewerFilter#select(org.eclipse.jface.viewers.Viewer,
   * java.lang.Object, java.lang.Object)
   */
  @Override
  public final boolean select(Viewer viewer, Object parentElement, Object element) {

    /* Filter not Active */
    if (fMatcher == null && fType == Type.SHOW_ALL)
      return true;

    return isElementVisible(viewer, element);
  }

  @Override
  public Object[] filter(Viewer viewer, Object parent, Object[] elements) {

    /* Filter not Active */
    if (fMatcher == null && fType == BookMarkFilter.Type.SHOW_ALL)
      return elements;

    return super.filter(viewer, parent, elements);
  }

  @Override
  public boolean isFilterProperty(Object element, String property) {
    return false; // This is handled in needsRefresh() already
  }

  /**
   * Get the Target of the Search. The Target is describing which elements to
   * search when a Text-Search is performed.
   *
   * @return Returns the SearchTarget of the Search as described in the
   * <code>SearchTarget</code> enumeration.
   */
  SearchTarget getSearchTarget() {
    return fSearchTarget;
  }

  /**
   * Set the Target of the Search. The Target is describing which elements to
   * search when a Text-Search is performed.
   *
   * @param searchTarget The SearchTarget of the Search as described in the
   * <code>SearchTarget</code> enumeration.
   */
  public void setSearchTarget(SearchTarget searchTarget) {
    fSearchTarget = searchTarget;
  }

  /**
   * Set the Type of this Filter. The Type is describing which elements are
   * filtered.
   *
   * @param type The Type of this Filter as described in the <code>Type</code>
   * enumeration.
   */
  public void setType(Type type) {
    if (fType != type)
      fType = type;
  }

  /**
   * Get the Type of this Filter. The Type is describing which elements are
   * filtered.
   *
   * @return Returns the Type of this Filter as described in the
   * <code>Type</code> enumeration.
   */
  Type getType() {
    return fType;
  }

  /**
   * The pattern string for which this filter should select elements in the
   * viewer.
   *
   * @param patternString
   */
  public void setPattern(String patternString) {
    if (patternString == null || patternString.equals("")) //$NON-NLS-1$
      fMatcher = null;
    else
      fMatcher = new StringMatcher(patternString + "*", true, false); //$NON-NLS-1$
  }

  /**
   * Answers whether the given String matches the pattern.
   *
   * @param string the String to test
   * @return whether the string matches the pattern
   */
  private boolean match(String string) {
    if (fMatcher == null)
      return true;

    return fMatcher.match(string);
  }

  boolean needsRefresh(Class<? extends IEntity> entity, Set<? extends ModelEvent> events) {

    /* In case the Filter is not active at all */
    if (fMatcher == null && fType == Type.SHOW_ALL)
      return false;

    /* Bookmark Event */
    if (entity.equals(IBookMark.class)) {
      if (fMatcher != null)
        return true;

      if (fType == Type.SHOW_NEVER_VISITED || fType == Type.SHOW_ERRONEOUS)
        return true;
    }

    /* Searchmark Event */
    else if (entity.equals(ISearchMark.class)) {
      if (fMatcher != null)
        return true;

      if (fType == Type.SHOW_NEW || fType == Type.SHOW_UNREAD)
        return true;
    }

    /* News Event */
    else if (entity.equals(INews.class)) {
      if (fType == Type.SHOW_NEW)
        return ModelUtils.isNewStateChange(events);
      else if (fType == Type.SHOW_UNREAD)
        return ModelUtils.isReadStateChange(events);
      else if (fType == Type.SHOW_STICKY)
        return ModelUtils.isStickyStateChange(events);
    }

    return false;
  }

  /**
   * Answers whether the given element in the given viewer matches the filter
   * pattern. This is a default implementation that will show a leaf element in
   * the tree based on whether the provided filter text matches the text of the
   * given element's text, or that of it's children (if the element has any).
   * Subclasses may override this method.
   *
   * @param viewer the tree viewer in which the element resides
   * @param element the element in the tree to check for a match
   * @return true if the element matches the filter pattern
   */
  boolean isElementVisible(Viewer viewer, Object element) {
    return isParentMatch(viewer, element) || isLeafMatch(viewer, element);
  }

  /**
   * Answers whether the given element is a valid selection in the filtered
   * tree. For example, if a tree has items that are categorized, the category
   * itself may not be a valid selection since it is used merely to organize the
   * elements.
   *
   * @param element
   * @return true if this element is eligible for automatic selection
   */
  boolean isElementSelectable(Object element) {
    return element != null;
  }

  /**
   * Check if the parent (category) is a match to the filter text. The default
   * behavior returns true if the element has at least one child element that is
   * a match with the filter text. Subclasses may override this method.
   *
   * @param viewer the viewer that contains the element
   * @param element the tree element to check
   * @return true if the given element has children that matches the filter text
   */
  private boolean isParentMatch(Viewer viewer, Object element) {
    if (!(viewer instanceof AbstractTreeViewer))
      return false;

    Object[] children = ((ITreeContentProvider) ((AbstractTreeViewer) viewer).getContentProvider()).getChildren(element);

    if ((children != null) && (children.length > 0))
      return filter(viewer, element, children).length > 0;

    return false;
  }

  /**
   * Check if the current (leaf) element is a match with the filter text. The
   * default behavior checks that the label of the element is a match.
   * Subclasses should override this method.
   *
   * @param viewer the viewer that contains the element
   * @param element the tree element to check
   * @return true if the given element's label matches the filter text
   */
  protected boolean isLeafMatch(@SuppressWarnings("unused")
  Viewer viewer, Object element) {

    /* Element is a BookMark */
    if (element instanceof IBookMark) {
      IBookMark bookmark = (IBookMark) element;

      /* First check the Pattern */
      if (fMatcher != null) {
        if (!wordMatches(bookmark))
          return false;
      }

      /* Show: All */
      if (fType == Type.SHOW_ALL)
        return true;

      /* Show: Feeds with New News */
      if (fType == Type.SHOW_NEW)
        return hasNewNews(bookmark.getFeedLinkReference());

      /* Show: Unread Feeds */
      else if (fType == Type.SHOW_UNREAD)
        return hasUnreadNews(bookmark.getFeedLinkReference());

      /* Show: Sticky Feeds */
      else if (fType == Type.SHOW_STICKY)
        return hasStickyNews(bookmark.getFeedLinkReference());

      /* Show: Feeds that had an Error while loading */
      else if (fType == Type.SHOW_ERRONEOUS)
        return bookmark.isErrorLoading();

      /* Show: Never visited Marks */
      else if (fType == Type.SHOW_NEVER_VISITED)
        return bookmark.getPopularity() <= 0;
    }

    /* Element is a SearchMark */
    else if (element instanceof ISearchMark) {
      ISearchMark mark = (ISearchMark) element;

      /* First check the Pattern */
      if (fMatcher != null) {
        if (!wordMatches(mark))
          return false;
      }

      /* Show: All */
      if (fType == Type.SHOW_ALL)
        return true;

      /* Show: New News */
      else if (fType == Type.SHOW_NEW)
        return mark.getResultCount(EnumSet.of(INews.State.NEW)) > 0;

      /* Show: Unread News */
      else if (fType == Type.SHOW_UNREAD)
        return mark.getResultCount(EnumSet.of(INews.State.NEW, INews.State.UNREAD, INews.State.UPDATED)) > 0;

      /* Show: Never visited Marks */
      else if (fType == Type.SHOW_NEVER_VISITED)
        return mark.getPopularity() <= 0;
    }

    return false;
  }

  private boolean hasUnreadNews(FeedLinkReference feedRef) {
    return fNewsService.getUnreadCount(feedRef) > 0;
  }

  private boolean hasStickyNews(FeedLinkReference feedRef) {
    return fNewsService.getStickyCount(feedRef) > 0;
  }

  private boolean hasNewNews(FeedLinkReference feedRef) {
    return fNewsService.getNewCount(feedRef) > 0;
  }

  /**
   * Take the given filter text and break it down into words using a
   * BreakIterator.
   *
   * @param text
   * @return an array of words
   */
  private String[] getWords(String text) {
    List<String> words = new ArrayList<String>();

    /*
     * Break the text up into words, separating based on whitespace and common
     * punctuation. Previously used String.split(..., "\\W"), where "\W" is a
     * regular expression (see the Javadoc for class Pattern). Need to avoid
     * both String.split and regular expressions, in order to compile against
     * JCL Foundation (bug 80053). Also need to do this in an NL-sensitive way.
     * The use of BreakIterator was suggested in bug 90579.
     */
    BreakIterator iter = BreakIterator.getWordInstance();
    iter.setText(text);
    int i = iter.first();
    while (i != java.text.BreakIterator.DONE && i < text.length()) {
      int j = iter.following(i);
      if (j == java.text.BreakIterator.DONE)
        j = text.length();

      /* match the word */
      if (Character.isLetterOrDigit(text.charAt(i))) {
        String word = text.substring(i, j);
        words.add(word);
      }
      i = j;
    }
    return words.toArray(new String[words.size()]);
  }

  private boolean wordMatches(IMark mark) {

    /* Search Name */
    if (fSearchTarget == SearchTarget.NAME)
      return wordMatches(mark.getName());

    /* Search Link */
    if (fSearchTarget == SearchTarget.LINK && mark instanceof IBookMark)
      return wordMatches(((IBookMark) mark).getFeedLinkReference().getLink().toString());

    /* Require a Feed from here on */
    if (!(mark instanceof IBookMark))
      return false;

    return false;
  }

  /**
   * Return whether or not if any of the words in text satisfy the match
   * critera.
   *
   * @param text the text to match
   * @return boolean <code>true</code> if one of the words in text satisifes
   * the match criteria.
   */
  protected boolean wordMatches(String text) {
    if (text == null)
      return false;

    /* If the whole text matches we are all set */
    if (match(text))
      return true;

    /* Otherwise check if any of the words of the text matches */
    String[] words = getWords(text);
    for (String word : words) {
      if (match(word))
        return true;
    }

    return false;
  }
}
TOP

Related Classes of org.rssowl.ui.internal.views.explorer.BookMarkFilter

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.