Package org.rssowl.ui.internal.search

Source Code of org.rssowl.ui.internal.search.SearchConditionList

/*   **********************************************************************  **
**   Copyright notice                                                       **
**                                                                          **
**   (c) 2005-2009 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.search;

import org.eclipse.core.runtime.Assert;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.resource.LocalResourceManager;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.ScrolledComposite;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.MenuItem;
import org.eclipse.swt.widgets.ToolBar;
import org.eclipse.swt.widgets.ToolItem;
import org.rssowl.core.Owl;
import org.rssowl.core.persist.IEntity;
import org.rssowl.core.persist.IModelFactory;
import org.rssowl.core.persist.INews;
import org.rssowl.core.persist.ISearchCondition;
import org.rssowl.core.persist.ISearchField;
import org.rssowl.core.persist.ISearchMark;
import org.rssowl.core.persist.SearchSpecifier;
import org.rssowl.ui.internal.OwlUI;
import org.rssowl.ui.internal.util.JobRunner;
import org.rssowl.ui.internal.util.LayoutUtils;

import java.util.ArrayList;
import java.util.List;

/**
* The <code>SearchConditionList</code> is a scrolled composite that allows to
* define a set of <code>ISearchCondition</code>s. The UI allows to add, remove
* and edit single Conditions.
*
* @author bpasero
*/
public class SearchConditionList extends ScrolledComposite {
  private List<SearchConditionItem> fItems;
  private final List<Integer> fFieldsToExclude;
  private Composite fContainer;
  private LocalResourceManager fResources;
  private Image fAddIcon;
  private Image fAddDisabledIcon;
  private Image fDeleteIcon;
  private Image fDeleteDisabledIcon;
  private boolean fModified;
  private int fVisibleItemCount = 3;

  /**
   * @param parent The parent Composite.
   * @param style The Style as defined by SWT constants.
   * @param conditions The initial conditions this List is showing.
   */
  public SearchConditionList(Composite parent, int style, List<ISearchCondition> conditions) {
    this(parent, style, conditions, null);
  }

  /**
   * @param parent The parent Composite.
   * @param style The Style as defined by SWT constants.
   * @param conditions The initial conditions this List is showing.
   * @param fieldsToExclude A list of search fields to exclude from the UI.
   */
  public SearchConditionList(Composite parent, int style, List<ISearchCondition> conditions, List<Integer> fieldsToExclude) {
    super(parent, style | SWT.V_SCROLL);
    fItems = new ArrayList<SearchConditionItem>();
    fFieldsToExclude = fieldsToExclude;
    fResources = new LocalResourceManager(JFaceResources.getResources(), this);

    initResources();
    initComponents(conditions);
  }

  /**
   * Sets the number of <code>SearchConditionItem</code>s that should be visible
   * in the List. If the number of items is higher, scrollbars will be shown
   * automatically.
   *
   * @param count the number of <code>SearchConditionItem</code>s that should be
   * visible in the List.
   */
  public void setVisibleItemCount(int count) {
    Assert.isLegal(count >= 0);
    fVisibleItemCount = count;
  }

  /**
   * Returns <code>TRUE</code> when this List has no items with a specific
   * value, and <code>FALSE</code> otherwise.
   *
   * @return <code>TRUE</code> when this List has no items with a specific
   * value, and <code>FALSE</code> otherwise.
   */
  public boolean isEmpty() {
    for (SearchConditionItem item : fItems) {
      if (item.hasValue())
        return false;
    }

    return true;
  }

  /*
   * @see org.eclipse.swt.widgets.Composite#computeSize(int, int, boolean)
   */
  @Override
  public Point computeSize(int wHint, int hHint, boolean changed) {
    Point point = super.computeSize(wHint, hHint, changed);

    /* Compute from Condition Item */
    if (fVisibleItemCount > 0 && fItems.size() > 0) {
      int itemHeight = fItems.get(0).computeSize(wHint, hHint).y + 4;
      point.y = fVisibleItemCount * itemHeight;
    }

    return point;
  }

  /**
   * Removes all but the first Items from the List.
   */
  public void reset() {
    setRedraw(false);
    try {

      /* Remove all Items */
      if (fItems.size() > 0) {
        List<SearchConditionItem> itemsToRemove = new ArrayList<SearchConditionItem>(fItems);
        for (SearchConditionItem itemToRemove : itemsToRemove) {
          itemToRemove.getParent().dispose();
          removeItem(itemToRemove);
        }
      }

      /* Add default */
      addItem(getDefaultCondition());
    } finally {
      setRedraw(true);
    }

    focusInput();
    fModified = true;
  }

  /**
   * Passes focus to the first item of this List.
   */
  public void focusInput() {
    focusInput(0);
  }

  /**
   * Passes focus to the Item in the list at the given index.
   *
   * @param index the index of the item to focus.
   */
  public void focusInput(int index) {
    if (fItems.size() > index)
      fItems.get(index).focusInput();
  }

  /**
   * @return Returns a List of <code>ISearchCondition</code> representing the
   * selected states.
   * @see SearchConditionList#createConditions(ISearchMark)
   */
  public List<ISearchCondition> createConditions() {
    return createConditions(null);
  }

  /**
   * @param searchmark The parent of the <code>ISearchCondition</code>s that are
   * being created.
   * @return Returns a List of <code>ISearchCondition</code> representing the
   * selected states.
   * @see SearchConditionList#createConditions()
   */
  public List<ISearchCondition> createConditions(ISearchMark searchmark) {
    List<ISearchCondition> conditions = new ArrayList<ISearchCondition>();

    /* For each Item */
    for (SearchConditionItem item : fItems) {
      ISearchCondition condition = item.createCondition(searchmark, true);
      if (condition != null)
        conditions.add(condition);
    }

    return conditions;
  }

  /**
   * Shows the List of <code>ISearchCondition</code> in this List.
   *
   * @param conditions the List of <code>ISearchCondition</code> to show in this
   * List.
   */
  public void showConditions(List<ISearchCondition> conditions) {
    fModified = true;
    setRedraw(false);
    try {

      /* Remove all */
      List<SearchConditionItem> itemsToRemove = new ArrayList<SearchConditionItem>(fItems);
      for (SearchConditionItem itemToRemove : itemsToRemove) {
        itemToRemove.getParent().dispose();
        removeItem(itemToRemove);
      }

      /* Add Conditions */
      if (conditions != null && !conditions.isEmpty()) {
        for (ISearchCondition condition : conditions)
          addItem(condition);
      } else
        addItem(getDefaultCondition());
    } finally {
      setRedraw(true);
    }
  }

  /**
   * Optimization: In order to check weather conditions in the list have been
   * modified, this method can be used. Note that this method will also return
   * <code>TRUE</code> if a condition was modified and then reset to its initial
   * value.
   *
   * @return Returns <code>TRUE</code> if the list of conditions was potentially
   * modified (conditions added, removed or updated) and <code>FALSE</code>
   * otherwise.
   */
  public boolean isModified() {
    if (fModified)
      return true;

    for (SearchConditionItem item : fItems) {
      if (item.isModified())
        return true;
    }

    return false;
  }

  private void initResources() {
    fAddIcon = OwlUI.getImage(fResources, "icons/etool16/add.gif"); //$NON-NLS-1$
    fAddDisabledIcon = OwlUI.getImage(fResources, "icons/dtool16/add.gif"); //$NON-NLS-1$
    fDeleteIcon = OwlUI.getImage(fResources, "icons/etool16/remove.gif"); //$NON-NLS-1$
    fDeleteDisabledIcon = OwlUI.getImage(fResources, "icons/dtool16/remove.gif"); //$NON-NLS-1$
  }

  private void initComponents(List<ISearchCondition> conditions) {

    /* Adjust Scrolled Composite */
    setLayout(new GridLayout(1, false));
    setExpandHorizontal(true);
    setExpandVertical(true);
    if (getVerticalBar() != null)
      getVerticalBar().setIncrement(10);

    /* Create the Container */
    fContainer = new Composite(this, SWT.NONE);
    fContainer.setLayout(LayoutUtils.createGridLayout(1, 0, 0));
    fContainer.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
    setContent(fContainer);

    /* Add Conditions */
    if (conditions != null && !conditions.isEmpty()) {
      for (ISearchCondition condition : conditions)
        addItem(condition);
    } else
      addItem(getDefaultCondition());

    /* Update Size */
    updateSize();
  }

  private ISearchCondition getDefaultCondition() {
    IModelFactory factory = Owl.getModelFactory();

    ISearchField field = factory.createSearchField(IEntity.ALL_FIELDS, INews.class.getName());
    ISearchCondition condition = factory.createSearchCondition(field, SearchSpecifier.CONTAINS_ALL, ""); //$NON-NLS-1$

    return condition;
  }

  SearchConditionItem addItem(ISearchCondition condition) {
    return addItem(condition, fItems.size());
  }

  SearchConditionItem addItem(ISearchCondition condition, int index) {
    return addItem(condition, index, false);
  }

  SearchConditionItem addItem(ISearchCondition condition, int index, boolean scroll) {
    boolean wasScrollbarShowing = getVerticalBar() != null ? getVerticalBar().isVisible() : false;

    /* Container for Item */
    final Composite itemContainer = new Composite(fContainer, SWT.NONE);
    itemContainer.setLayout(LayoutUtils.createGridLayout(2, 0, 0, 0, 0, false));
    itemContainer.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, true, false));

    /* Create Item */
    final SearchConditionItem item = new SearchConditionItem(itemContainer, SWT.NONE, condition, fFieldsToExclude);
    item.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, true, false));

    /* Create Button Box */
    final ToolBar buttonBar = new ToolBar(itemContainer, SWT.FLAT);
    buttonBar.setLayoutData(new GridData(SWT.END, SWT.CENTER, false, false));

    /* Button to add Condition */
    ToolItem addButton = new ToolItem(buttonBar, SWT.DROP_DOWN);
    addButton.setImage(fAddIcon);
    addButton.setDisabledImage(fAddDisabledIcon);
    addButton.setToolTipText(Messages.SearchConditionList_ADD_CONDITION);

    /* Add Menu */
    final Menu conditionMenu = new Menu(buttonBar);
    createConditionMenu(conditionMenu, item);
    addButton.addListener(SWT.Selection, new Listener() {
      public void handleEvent(Event event) {
        if (event.detail == SWT.ARROW) {
          Rectangle rect = item.getBounds();
          Point pt = new Point(rect.x, rect.y + rect.height);
          pt = buttonBar.toDisplay(pt);
          conditionMenu.setLocation(pt.x, pt.y);
          conditionMenu.setVisible(true);
        } else
          onAdd(item);
      }
    });

    buttonBar.addDisposeListener(new DisposeListener() {
      public void widgetDisposed(DisposeEvent e) {
        conditionMenu.dispose();
      }
    });

    /* Button to delete Condition */
    ToolItem deleteButton = new ToolItem(buttonBar, SWT.PUSH);
    deleteButton.setImage(fDeleteIcon);
    deleteButton.setDisabledImage(fDeleteDisabledIcon);
    deleteButton.setToolTipText(Messages.SearchConditionList_DELETE_CONDITION);
    deleteButton.addSelectionListener(new SelectionAdapter() {
      @Override
      public void widgetSelected(SelectionEvent e) {
        JobRunner.runInUIThread(0, true, buttonBar, new Runnable() {
          public void run() {
            onDelete(item, itemContainer);
          }
        });
      }
    });

    /* Add to the End */
    boolean addedToEnd = false;
    if (index == fItems.size()) {
      addedToEnd = true;
      fItems.add(item);
    }

    /* Add to specific Index */
    else {
      SearchConditionItem oldItem = fItems.get(index);
      fItems.add(index, item);
      item.getParent().moveAbove(oldItem.getParent());
    }

    /* Force Layout */
    layout(true, true);
    update();

    /* Update Size */
    updateSize();
    OwlUI.adjustSizeForScrollbar(getShell(), getVerticalBar(), wasScrollbarShowing);

    /* Scroll to Bottom if added as last element */
    if (scroll && addedToEnd)
      setOrigin(0, getContent().getSize().y);

    return item;
  }

  private void createConditionMenu(Menu menu, SearchConditionItem item) {
    IModelFactory factory = Owl.getModelFactory();
    String news = INews.class.getName();

    if (fFieldsToExclude == null || !fFieldsToExclude.contains(IEntity.ALL_FIELDS)) {
      MenuItem mItem = new MenuItem(menu, SWT.PUSH);
      mItem.setText(Messages.SearchConditionList_ENTIRE_NEWS);
      hookSelectionListener(mItem, item, factory.createSearchField(IEntity.ALL_FIELDS, news));

      new MenuItem(menu, SWT.SEPARATOR);
    }

    if (fFieldsToExclude == null || !fFieldsToExclude.contains(INews.STATE)) {
      MenuItem mItem = new MenuItem(menu, SWT.PUSH);
      mItem.setText(Messages.SearchConditionList_STATE);
      hookSelectionListener(mItem, item, factory.createSearchField(INews.STATE, news));
    }

    if (fFieldsToExclude == null || !fFieldsToExclude.contains(INews.LOCATION)) {
      MenuItem mItem = new MenuItem(menu, SWT.PUSH);
      mItem.setText(Messages.SearchConditionList_LOCATION);
      hookSelectionListener(mItem, item, factory.createSearchField(INews.LOCATION, news));

      new MenuItem(menu, SWT.SEPARATOR);
    }

    if (fFieldsToExclude == null || !fFieldsToExclude.contains(INews.TITLE)) {
      MenuItem mItem = new MenuItem(menu, SWT.PUSH);
      mItem.setText(Messages.SearchConditionList_TITLE);
      hookSelectionListener(mItem, item, factory.createSearchField(INews.TITLE, news));
    }

    if (fFieldsToExclude == null || !fFieldsToExclude.contains(INews.DESCRIPTION)) {
      MenuItem mItem = new MenuItem(menu, SWT.PUSH);
      mItem.setText(Messages.SearchConditionList_DESCRIPTION);
      hookSelectionListener(mItem, item, factory.createSearchField(INews.DESCRIPTION, news));
    }

    if (fFieldsToExclude == null || !fFieldsToExclude.contains(INews.AUTHOR)) {
      MenuItem mItem = new MenuItem(menu, SWT.PUSH);
      mItem.setText(Messages.SearchConditionList_AUTHOR);
      hookSelectionListener(mItem, item, factory.createSearchField(INews.AUTHOR, news));
    }

    if (fFieldsToExclude == null || !fFieldsToExclude.contains(INews.CATEGORIES)) {
      MenuItem mItem = new MenuItem(menu, SWT.PUSH);
      mItem.setText(Messages.SearchConditionList_CATEGORY);
      hookSelectionListener(mItem, item, factory.createSearchField(INews.CATEGORIES, news));
    }

    MenuItem mItem = new MenuItem(menu, SWT.CASCADE);
    mItem.setText(Messages.SearchConditionList_DATE);

    Menu dateMenu = new Menu(mItem);
    mItem.setMenu(dateMenu);

    if (fFieldsToExclude == null || !fFieldsToExclude.contains(INews.AGE_IN_DAYS)) {
      mItem = new MenuItem(dateMenu, SWT.PUSH);
      mItem.setText(Messages.SearchConditionList_AGE);
      hookSelectionListener(mItem, item, factory.createSearchField(INews.AGE_IN_DAYS, news));

      new MenuItem(dateMenu, SWT.SEPARATOR);
    }

    if (fFieldsToExclude == null || !fFieldsToExclude.contains(INews.MODIFIED_DATE)) {
      mItem = new MenuItem(dateMenu, SWT.PUSH);
      mItem.setText(Messages.SearchConditionList_DATE_MODIFIED);
      hookSelectionListener(mItem, item, factory.createSearchField(INews.MODIFIED_DATE, news));
    }

    if (fFieldsToExclude == null || !fFieldsToExclude.contains(INews.PUBLISH_DATE)) {
      mItem = new MenuItem(dateMenu, SWT.PUSH);
      mItem.setText(Messages.SearchConditionList_DATE_PUBLISHED);
      hookSelectionListener(mItem, item, factory.createSearchField(INews.PUBLISH_DATE, news));
    }

    if (fFieldsToExclude == null || !fFieldsToExclude.contains(INews.RECEIVE_DATE)) {
      mItem = new MenuItem(dateMenu, SWT.PUSH);
      mItem.setText(Messages.SearchConditionList_DATE_RECEIVED);
      hookSelectionListener(mItem, item, factory.createSearchField(INews.RECEIVE_DATE, news));
    }

    mItem = new MenuItem(menu, SWT.SEPARATOR);

    mItem = new MenuItem(menu, SWT.CASCADE);
    mItem.setText(Messages.SearchConditionList_OTHER);

    Menu otherMenu = new Menu(mItem);
    mItem.setMenu(otherMenu);

    if (fFieldsToExclude == null || !fFieldsToExclude.contains(INews.HAS_ATTACHMENTS)) {
      mItem = new MenuItem(otherMenu, SWT.PUSH);
      mItem.setText(Messages.SearchConditionList_HAS_ATTACHMENTS);
      hookSelectionListener(mItem, item, factory.createSearchField(INews.HAS_ATTACHMENTS, news));
    }

    if (fFieldsToExclude == null || !fFieldsToExclude.contains(INews.ATTACHMENTS_CONTENT)) {
      mItem = new MenuItem(otherMenu, SWT.PUSH);
      mItem.setText(Messages.SearchConditionList_ATTACHMENT);
      hookSelectionListener(mItem, item, factory.createSearchField(INews.ATTACHMENTS_CONTENT, news));
    }

    new MenuItem(otherMenu, SWT.SEPARATOR);

    if (fFieldsToExclude == null || !fFieldsToExclude.contains(INews.SOURCE)) {
      mItem = new MenuItem(otherMenu, SWT.PUSH);
      mItem.setText(Messages.SearchConditionList_SOURCE);
      hookSelectionListener(mItem, item, factory.createSearchField(INews.SOURCE, news));
    }

    if (fFieldsToExclude == null || !fFieldsToExclude.contains(INews.LINK)) {
      mItem = new MenuItem(otherMenu, SWT.PUSH);
      mItem.setText(Messages.SearchConditionList_LINK);
      hookSelectionListener(mItem, item, factory.createSearchField(INews.LINK, news));
    }

    if (fFieldsToExclude == null || !fFieldsToExclude.contains(INews.IS_FLAGGED)) {
      mItem = new MenuItem(otherMenu, SWT.PUSH);
      mItem.setText(Messages.SearchConditionList_IS_STICKY);
      hookSelectionListener(mItem, item, factory.createSearchField(INews.IS_FLAGGED, news));
    }

    if (fFieldsToExclude == null || !fFieldsToExclude.contains(INews.FEED)) {
      mItem = new MenuItem(otherMenu, SWT.PUSH);
      mItem.setText(Messages.SearchConditionList_FEED);
      hookSelectionListener(mItem, item, factory.createSearchField(INews.FEED, news));
    }

    if (fFieldsToExclude == null || !fFieldsToExclude.contains(INews.LABEL)) {
      mItem = new MenuItem(otherMenu, SWT.PUSH);
      mItem.setText(Messages.SearchConditionList_LABEL);
      hookSelectionListener(mItem, item, factory.createSearchField(INews.LABEL, news));
    }
  }

  private void hookSelectionListener(MenuItem item, final SearchConditionItem condition, final ISearchField field) {
    item.addSelectionListener(new SelectionAdapter() {
      @Override
      public void widgetSelected(SelectionEvent e) {
        onAdd(condition, field);
      }
    });
  }

  int indexOf(SearchConditionItem item) {
    return fItems.indexOf(item);
  }

  void onAdd(SearchConditionItem selectedItem, ISearchField field) {
    ISearchCondition condition = createCondition(selectedItem.createCondition(null, false));
    condition.setField(field);

    SearchConditionItem addedItem = addItem(condition, indexOf(selectedItem) + 1, true);
    addedItem.focusInput();

    fModified = true;
  }

  void onAdd(SearchConditionItem selectedItem) {
    ISearchCondition condition = createCondition(selectedItem.createCondition(null, false));
    SearchConditionItem addedItem = addItem(condition, indexOf(selectedItem) + 1, true);
    addedItem.focusInput();

    fModified = true;
  }

  void onDelete(final SearchConditionItem item, final Composite itemContainer) {
    boolean wasScrollbarShowing = getVerticalBar() != null ? getVerticalBar().isVisible() : false;

    /* Delete */
    itemContainer.dispose();
    removeItem(item);
    fModified = true;

    /* Restore Default if required */
    if (fItems.size() == 0)
      addItem(getDefaultCondition()).focusInput();

    OwlUI.adjustSizeForScrollbar(getShell(), getVerticalBar(), wasScrollbarShowing);
  }

  private ISearchCondition createCondition(ISearchCondition current) {
    IModelFactory factory = Owl.getModelFactory();
    ISearchField field = factory.createSearchField(current.getField().getId(), current.getField().getEntityName());
    return factory.createSearchCondition(field, current.getSpecifier(), ""); //$NON-NLS-1$
  }

  void removeItem(SearchConditionItem item) {

    /* Dispose and Remove */
    item.dispose();
    fItems.remove(item);

    /* Force Layout */
    layout(true, true);
    update();

    /* Update Size */
    updateSize();
  }

  private void updateSize() {
    setMinSize(fContainer.computeSize(SWT.DEFAULT, SWT.DEFAULT));
  }
}
TOP

Related Classes of org.rssowl.ui.internal.search.SearchConditionList

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.