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

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

/*   **********************************************************************  **
**   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.views.explorer;

import org.eclipse.core.runtime.Assert;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.GroupMarker;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.IMenuListener;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.IToolBarManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.jface.action.ToolBarManager;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.util.IPropertyChangeListener;
import org.eclipse.jface.util.LocalSelectionTransfer;
import org.eclipse.jface.util.PropertyChangeEvent;
import org.eclipse.jface.viewers.DoubleClickEvent;
import org.eclipse.jface.viewers.IDoubleClickListener;
import org.eclipse.jface.viewers.IElementComparer;
import org.eclipse.jface.viewers.IInputProvider;
import org.eclipse.jface.viewers.IOpenListener;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.ISelectionProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ITreeViewerListener;
import org.eclipse.jface.viewers.OpenEvent;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.TreeExpansionEvent;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.dnd.DND;
import org.eclipse.swt.dnd.TextTransfer;
import org.eclipse.swt.dnd.Transfer;
import org.eclipse.swt.dnd.URLTransfer;
import org.eclipse.swt.events.KeyAdapter;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.MouseAdapter;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.MenuItem;
import org.eclipse.swt.widgets.Text;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeItem;
import org.eclipse.ui.IActionDelegate;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IEditorReference;
import org.eclipse.ui.IPartListener2;
import org.eclipse.ui.IViewSite;
import org.eclipse.ui.IWorkbenchActionConstants;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.IWorkbenchPartReference;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.actions.ActionFactory;
import org.eclipse.ui.dialogs.PreferencesUtil;
import org.eclipse.ui.part.ViewPart;
import org.eclipse.ui.progress.IWorkbenchSiteProgressService;
import org.rssowl.core.Owl;
import org.rssowl.core.internal.persist.pref.DefaultPreferences;
import org.rssowl.core.persist.IBookMark;
import org.rssowl.core.persist.IEntity;
import org.rssowl.core.persist.IFolder;
import org.rssowl.core.persist.IFolderChild;
import org.rssowl.core.persist.IMark;
import org.rssowl.core.persist.INews;
import org.rssowl.core.persist.INewsMark;
import org.rssowl.core.persist.IPreference;
import org.rssowl.core.persist.dao.DynamicDAO;
import org.rssowl.core.persist.dao.IPreferenceDAO;
import org.rssowl.core.persist.event.FolderAdapter;
import org.rssowl.core.persist.event.FolderEvent;
import org.rssowl.core.persist.event.FolderListener;
import org.rssowl.core.persist.pref.IPreferenceScope;
import org.rssowl.core.persist.reference.BookMarkReference;
import org.rssowl.core.persist.reference.FeedLinkReference;
import org.rssowl.core.persist.reference.FolderReference;
import org.rssowl.core.persist.reference.ModelReference;
import org.rssowl.core.util.CoreUtils;
import org.rssowl.core.util.ITreeNode;
import org.rssowl.core.util.ModelTreeNode;
import org.rssowl.core.util.StringUtils;
import org.rssowl.core.util.TreeTraversal;
import org.rssowl.ui.internal.ApplicationWorkbenchWindowAdvisor;
import org.rssowl.ui.internal.ContextMenuCreator;
import org.rssowl.ui.internal.Controller;
import org.rssowl.ui.internal.EntityGroup;
import org.rssowl.ui.internal.OwlUI;
import org.rssowl.ui.internal.ShareProvider;
import org.rssowl.ui.internal.StatusLineUpdater;
import org.rssowl.ui.internal.actions.AggregateFolderAction;
import org.rssowl.ui.internal.actions.DeleteTypesAction;
import org.rssowl.ui.internal.actions.EntityPropertyDialogAction;
import org.rssowl.ui.internal.actions.FindAction;
import org.rssowl.ui.internal.actions.NewBookMarkAction;
import org.rssowl.ui.internal.actions.NewFolderAction;
import org.rssowl.ui.internal.actions.NewNewsBinAction;
import org.rssowl.ui.internal.actions.NewSearchMarkAction;
import org.rssowl.ui.internal.actions.OpenInBrowserAction;
import org.rssowl.ui.internal.actions.ReloadTypesAction;
import org.rssowl.ui.internal.actions.RetargetActions;
import org.rssowl.ui.internal.actions.SearchInTypeAction;
import org.rssowl.ui.internal.actions.SendLinkAction;
import org.rssowl.ui.internal.dialogs.ManageSetsDialog;
import org.rssowl.ui.internal.dialogs.preferences.SharingPreferencesPage;
import org.rssowl.ui.internal.editors.feed.FeedViewInput;
import org.rssowl.ui.internal.editors.feed.PerformAfterInputSet;
import org.rssowl.ui.internal.undo.UndoStack;
import org.rssowl.ui.internal.util.EditorUtils;
import org.rssowl.ui.internal.util.JobRunner;
import org.rssowl.ui.internal.util.WidgetTreeNode;

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

/**
* <p>
* TODO The underlying TreeViewer is not yet supporting contributed
* Label-Decorator, because the used LabelProvider is not extending
* ILabelProvider. Add this code to provide the decorations from contributions:
* <code>
* ILabelDecorator decorator = PlatformUI.getWorkbench().getDecoratorManager().getLabelDecorator();
* fViewer.setLabelProvider(new DecoratingLabelProvider(new BookMarkLabelProvider(), decorator);
* </code>
* </p>
*
* @author bpasero
*/
public class BookMarkExplorer extends ViewPart {

  /** ID of this View */
  public static final String VIEW_ID = "org.rssowl.ui.BookMarkExplorer"; //$NON-NLS-1$

  /** IDs of Action: Next Bookmark-Set */
  public static final String NEXT_SET_ACTION = "org.rssowl.ui.internal.views.explorer.NextSetAction"; //$NON-NLS-1$

  /** IDs of Action: Previous Bookmark-Set */
  public static final String PREVIOUS_SET_ACTION = "org.rssowl.ui.internal.views.explorer.PreviousSetAction"; //$NON-NLS-1$

  /* Local Setting Constants */
  private static final String PREF_SELECTED_FOLDER_CHILD = "org.rssowl.ui.internal.views.explorer.SelectedFolderChild"; //$NON-NLS-1$
  private static final String PREF_SELECTED_BOOKMARK_SET = "org.rssowl.ui.internal.views.explorer.SelectedBookMarkSet"; //$NON-NLS-1$
  private static final String PREF_EXPANDED_NODES = "org.rssowl.ui.internal.views.explorer.ExpandedNodes"; //$NON-NLS-1$

  /* Local Actions */
  private static final String GROUP_ACTION = "org.rssowl.ui.internal.views.explorer.GroupAction"; //$NON-NLS-1$
  private static final String FILTER_ACTION = "org.rssowl.ui.internal.views.explorer.FilterAction"; //$NON-NLS-1$

  /* Settings */
  private IPreferenceScope fGlobalPreferences;
  private List<Long> fExpandedNodes;
  private boolean fBeginSearchOnTyping;
  private boolean fAlwaysShowSearch;
  private boolean fSortByName;
  private BookMarkFilter.Type fFilterType;
  private BookMarkGrouping.Type fGroupingType;
  private IFolder fSelectedBookMarkSet;
  private boolean fLinkingEnabled;
  private boolean fFaviconsEnabled;
  private long fLastSelectedFolderChild;

  /* Viewer Classes */
  private TreeViewer fViewer;
  private BookMarkContentProvider fContentProvider;
  private BookMarkLabelProvider fLabelProvider;
  private BookMarkSorter fBookMarkComparator;
  private BookMarkFilter fBookMarkFilter;
  private BookMarkGrouping fBookMarkGrouping;

  /* Widgets */
  private Label fSeparator;
  private Composite fSearchBarContainer;
  private BookMarkSearchbar fSearchBar;
  private IToolBarManager fToolBarManager;

  /* BookMark Sets */
  private Set<IFolder> fRootFolders;

  /* Misc. */
  private IViewSite fViewSite;
  private IStructuredSelection fLastSelection;
  private FolderListener fFolderListener;
  private IPartListener2 fPartListener;
  private IPreferenceDAO fPrefDAO;
  private IPropertyChangeListener fPropertyChangeListener;
  private boolean fBlockSaveState;
  private BookMarkFilter.Type fLastFilterType;
  private BookMarkGrouping.Type fLastGroupType;

  /**
   * Returns the preferences key for the selected bookmark set for the given
   * workbench window.
   *
   * @param window the active workbench window.
   * @return the preferences key for the selected bookmark set for the given
   * workbench window.
   */
  public static String getSelectedBookMarkSetPref(IWorkbenchWindow window) {
    int windowIndex = OwlUI.getWindowIndex(window);
    return PREF_SELECTED_BOOKMARK_SET + windowIndex;
  }

  /*
   * @see org.eclipse.ui.part.WorkbenchPart#createPartControl(org.eclipse.swt.widgets.Composite)
   */
  @Override
  public void createPartControl(Composite parent) {

    /* Update Parent */
    GridLayout layout = new GridLayout(1, false);
    layout.marginWidth = 0;
    layout.marginHeight = 0;
    layout.verticalSpacing = 0;

    parent.setLayout(layout);
    parent.setBackground(parent.getDisplay().getSystemColor(SWT.COLOR_LIST_BACKGROUND));

    /* Create TreeViewer */
    createViewer(parent);

    /* Restore Expanded Elements */
    restoreExpandedElements();

    /* Restore Selection if linking is disabled */
    if (fLastSelectedFolderChild > 0 && !fLinkingEnabled)
      fViewer.setSelection(new StructuredSelection(new BookMarkReference(fLastSelectedFolderChild)), true);

    /* Hook into Statusline */
    fViewer.addSelectionChangedListener(new StatusLineUpdater(getViewSite().getActionBars().getStatusLineManager()));

    /* Hook into Global Actions */
    hookGlobalActions();

    /* Hook contextual Menu */
    hookContextualMenu();

    /* Hook into Toolbar */
    hookToolBar();

    /* Hook into View Dropdown */
    hookViewMenu();

    /* Register Listeners */
    registerListeners();

    /* Propagate Selection Events */
    fViewSite.setSelectionProvider(fViewer);

    /* Create the Search Bar */
    createSearchBar(parent);

    /* Show Busy when reload occurs */
    IWorkbenchSiteProgressService service = (IWorkbenchSiteProgressService) fViewSite.getAdapter(IWorkbenchSiteProgressService.class);
    service.showBusyForFamily(Controller.getDefault().getReloadFamily());
  }

  private void createViewer(Composite parent) {

    /* TreeViewer */
    fViewer = new BookMarkViewer(this, parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL);
    fViewer.getControl().setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
    fViewer.getControl().setData(ApplicationWorkbenchWindowAdvisor.FOCUSLESS_SCROLL_HOOK, new Object());
    fViewer.getControl().setFont(OwlUI.getThemeFont(OwlUI.BKMRK_EXPLORER_FONT_ID, SWT.NORMAL));

    /* Setup Drag & Drop Support */
    initDragAndDrop();

    /* Add a custom Comparer */
    fViewer.setComparer(getComparer());
    fViewer.setUseHashlookup(true);

    /* Create ContentProvider */
    fContentProvider = new BookMarkContentProvider();
    fViewer.setContentProvider(fContentProvider);

    /* Create LabelProvider */
    fLabelProvider = new BookMarkLabelProvider();
    fLabelProvider.setUseFavicons(fFaviconsEnabled);
    fViewer.setLabelProvider(fLabelProvider);

    /* Apply Sorter */
    fBookMarkComparator = new BookMarkSorter();
    if (fSortByName)
      fBookMarkComparator.setType(BookMarkSorter.Type.SORT_BY_NAME);
    fViewer.setComparator(fBookMarkComparator);

    /* Apply Filter */
    fBookMarkFilter = new BookMarkFilter();
    fBookMarkFilter.setType(fFilterType);
    fViewer.addFilter(fBookMarkFilter);

    /* Create Grouper */
    fBookMarkGrouping = new BookMarkGrouping();
    fBookMarkGrouping.setType(fGroupingType);

    /* Let the ContentProvider know */
    fContentProvider.setBookmarkFilter(fBookMarkFilter);
    fContentProvider.setBookmarkGrouping(fBookMarkGrouping);

    /* Set the initial Input based on selected Bookmark Set */
    fViewer.setInput(fSelectedBookMarkSet);

    /* Update Saved Searches if not yet done */
    JobRunner.runInBackgroundThread(50, new Runnable() {
      public void run() {
        Controller.getDefault().getSavedSearchService().updateSavedSearches(false);
      }
    });

    /* Enable "Link to FeedView" */
    fViewer.addPostSelectionChangedListener(new ISelectionChangedListener() {
      public void selectionChanged(SelectionChangedEvent event) {
        onSelectionChanged(event);
      }
    });

    /* Hook Doubleclick Support */
    fViewer.addDoubleClickListener(new IDoubleClickListener() {
      public void doubleClick(DoubleClickEvent event) {
        onDoubleClick(event);
      }
    });

    /* Hook Open Support */
    fViewer.addOpenListener(new IOpenListener() {
      public void open(OpenEvent event) {
        OwlUI.openInFeedView(fViewSite.getPage(), (IStructuredSelection) fViewer.getSelection());
      }
    });

    /* Aggregate Folder on Mouse Middle Click */
    fViewer.getTree().addMouseListener(new MouseAdapter() {
      @Override
      public void mouseUp(MouseEvent e) {
        if (e.button == 2)
          onMouseMiddleClick(fViewer.getTree().getItem(new Point(e.x, e.y)));
      }
    });

    /* Custom Owner Drawn for Groups */
    if (!OwlUI.isHighContrast()) {
      fViewer.getControl().addListener(SWT.EraseItem, new Listener() {
        public void handleEvent(Event event) {
          Object element = event.item.getData();
          fLabelProvider.erase(event, element);
        }
      });
    }

    /* Update List of Expanded Nodes */
    fViewer.addTreeListener(new ITreeViewerListener() {
      public void treeExpanded(TreeExpansionEvent event) {
        onTreeEvent(event.getElement(), true);
      }

      public void treeCollapsed(TreeExpansionEvent event) {
        onTreeEvent(event.getElement(), false);
      }
    });

    /* Link if enabled */
    if (fLinkingEnabled) {
      IWorkbenchPart activePart = fViewSite.getPage().getActivePart();
      if (activePart instanceof IEditorPart)
        editorActivated((IEditorPart) activePart);
    }
  }

  private void initDragAndDrop() {
    int ops = DND.DROP_COPY | DND.DROP_MOVE | DND.DROP_LINK;
    Transfer[] transfers = new Transfer[] { LocalSelectionTransfer.getTransfer(), TextTransfer.getInstance(), URLTransfer.getInstance() };
    BookMarkDNDImpl bookmarkDND = new BookMarkDNDImpl(this, fViewer);

    /* Drag Support */
    fViewer.addDragSupport(ops, transfers, bookmarkDND);

    /* Drop Support */
    fViewer.addDropSupport(ops, transfers, bookmarkDND);
  }

  private void onSelectionChanged(SelectionChangedEvent event) {
    fLastSelection = (IStructuredSelection) event.getSelection();
    if (fLinkingEnabled)
      linkToFeedView(fLastSelection);
  }

  private void onDoubleClick(DoubleClickEvent event) {
    IStructuredSelection selection = (IStructuredSelection) event.getSelection();
    Object firstElem = selection.getFirstElement();

    /* Expand / Collapse Folders */
    if (firstElem instanceof IFolder || firstElem instanceof EntityGroup) {
      boolean expandedState = !fViewer.getExpandedState(firstElem);
      fViewer.setExpandedState(firstElem, expandedState);
      onTreeEvent(firstElem, expandedState);
    }
  }

  private void onMouseMiddleClick(TreeItem item) {
    if (item != null && item.getData() instanceof IFolder) {
      AggregateFolderAction action = new AggregateFolderAction();
      action.setActivePart(null, this);
      action.selectionChanged(null, new StructuredSelection(item.getData()));
      action.run(null);
    }
  }

  private void onTreeEvent(Object element, boolean expanded) {

    /* Element expanded - add to List of expanded Nodes */
    if (expanded) {
      if (element instanceof IFolder)
        fExpandedNodes.add(((IFolder) element).getId());
      else if (element instanceof EntityGroup)
        fExpandedNodes.add(((EntityGroup) element).getId());
    }

    /* Element collapsed - remove from List of expanded Nodes */
    else {
      if (element instanceof IFolder)
        fExpandedNodes.remove(((IFolder) element).getId());
      else if (element instanceof EntityGroup)
        fExpandedNodes.remove(((EntityGroup) element).getId());
    }
  }

  /*
   * This Comparer is used to optimize some operations on the Viewer being used.
   * When deleting Entities, the Delete-Event is providing a reference to the
   * deleted Entity, which can not be resolved anymore. This Comparer will
   * return <code>TRUE</code> for a reference compared with an Entity that has
   * the same ID and is belonging to the same Entity. At any time, it _must_ be
   * avoided to call add, update or refresh with passing in a Reference!
   */
  private IElementComparer getComparer() {
    return new IElementComparer() {
      public boolean equals(Object a, Object b) {

        /* Quickyly check this common case */
        if (a == b && a != null)
          return true;

        /* Specially handle this reference */
        if (a instanceof FeedLinkReference || b instanceof FeedLinkReference) {
          FeedLinkReference ref1 = null;
          FeedLinkReference ref2 = null;

          if (a instanceof IBookMark)
            ref1 = ((IBookMark) a).getFeedLinkReference();
          else if (a instanceof FeedLinkReference)
            ref1 = ((FeedLinkReference) a);

          if (b instanceof IBookMark)
            ref2 = ((IBookMark) b).getFeedLinkReference();
          else if (b instanceof FeedLinkReference)
            ref2 = ((FeedLinkReference) b);

          if (ref1 != null)
            return ref1.equals(ref2);

          return false;
        }

        /* Handle Non Feed-Link-Reference */
        long id1 = 0;
        long id2 = 0;

        if (a instanceof IEntity)
          id1 = ((IEntity) a).getId();
        else if (a instanceof ModelReference)
          id1 = ((ModelReference) a).getId();
        else if (a instanceof EntityGroup)
          id1 = ((EntityGroup) a).getId();

        if (b instanceof IEntity)
          id2 = ((IEntity) b).getId();
        else if (b instanceof ModelReference)
          id2 = ((ModelReference) b).getId();
        else if (b instanceof EntityGroup)
          id2 = ((EntityGroup) b).getId();

        return id1 == id2;
      }

      public int hashCode(Object element) {
        return element.hashCode();
      }
    };
  }

  private void linkToFeedView(IStructuredSelection selection) {

    /* Only Link if this is the active Part */
    if (this != fViewSite.getPage().getActivePart())
      return;

    /* Only Link for Single Selections */
    if (selection.size() == 1) {
      Object element = selection.getFirstElement();

      /* Find the Editor showing given Selection */
      IWorkbenchPage activePage = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage();
      IEditorReference[] editorReferences = activePage.getEditorReferences();
      IEditorReference reference = EditorUtils.findEditor(editorReferences, element);
      if (reference != null)
        activePage.bringToTop(reference.getPart(true));
    }
  }

  private void editorActivated(IEditorPart part) {
    if (!fLinkingEnabled || part == null)
      return;

    /* Try to select and reveal editor input in the Explorer */
    IEditorInput editorInput = part.getEditorInput();
    if (editorInput instanceof FeedViewInput)
      reveal(((FeedViewInput) editorInput).getMark(), false);
  }

  /**
   * @return <code>true</code> if the explorer is linked to the feed view and
   * <code>false</code> otherwise.
   */
  public boolean isLinkingEnabled() {
    return fLinkingEnabled;
  }

  /**
   * @param element the folder child to make visible and select.
   * @param expand if <code>true</code> expand the element, <code>false</code>
   * otherwise.
   */
  public void reveal(IFolderChild element, boolean expand) {

    /* Return early if hidden */
    if (!fViewSite.getPage().isPartVisible(this))
      return;

    /* Change Set if required */
    IFolderChild child = element;
    while (child.getParent() != null)
      child = child.getParent();

    if (!fSelectedBookMarkSet.equals(child))
      changeSet((IFolder) child);

    /* Set Selection */
    fViewer.setSelection(new StructuredSelection(element), true);

    /* Expand if Set */
    if (expand) {
      fViewer.setExpandedState(element, true);
      fExpandedNodes.add(element.getId());
    }
  }

  void changeSet(IFolder folder) {

    /* Save Expanded Elements */
    saveExpandedElements();

    /* Set new Input */
    fSelectedBookMarkSet = folder;
    fViewer.setInput(fSelectedBookMarkSet);

    /* Restore Expanded Elements */
    fExpandedNodes.clear();
    loadExpandedElements();
    fViewer.getControl().setRedraw(false);
    try {
      restoreExpandedElements();
    } finally {
      fViewer.getControl().setRedraw(true);
    }

    /* Update Set Actions */
    fViewSite.getActionBars().getToolBarManager().find(PREVIOUS_SET_ACTION).update(IAction.ENABLED);
    fViewSite.getActionBars().getToolBarManager().find(NEXT_SET_ACTION).update(IAction.ENABLED);

    /* Save the new selected Set in Preferences */
    IPreference pref = fPrefDAO.loadOrCreate(getSelectedBookMarkSetPref(fViewSite.getWorkbenchWindow()));
    pref.putLongs(fSelectedBookMarkSet.getId());
    fPrefDAO.save(pref);
  }

  private void createSearchBar(final Composite parent) {

    /* Add Separator between Tree and Search Bar */
    fSeparator = new Label(parent, SWT.SEPARATOR | SWT.HORIZONTAL);
    fSeparator.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, true, false));

    /* Container for the SearchBar */
    fSearchBarContainer = new Composite(parent, SWT.NONE);
    fSearchBarContainer.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, true, false));

    /* Hide Searchbar in case settings tell so */
    ((GridData) fSeparator.getLayoutData()).exclude = !fAlwaysShowSearch;
    ((GridData) fSearchBarContainer.getLayoutData()).exclude = !fAlwaysShowSearch;

    /* Apply Layout */
    GridLayout searchBarLayout = new GridLayout(1, false);
    searchBarLayout.marginHeight = 2;
    searchBarLayout.marginWidth = 2;
    fSearchBarContainer.setLayout(searchBarLayout);

    /* Create the SearchBar */
    fSearchBar = new BookMarkSearchbar(fViewSite, fSearchBarContainer, fViewer, fBookMarkFilter);

    /* Show the SearchBar on Printable Key pressed */
    fViewer.getControl().addKeyListener(new KeyAdapter() {
      @Override
      public void keyPressed(KeyEvent e) {

        /* Feature not Used, return */
        if (!fBeginSearchOnTyping)
          return;

        /* Transfer typed key into SearchBar */
        if (e.character > 0x20 && e.character != SWT.DEL) {
          setSearchBarVisible(true);

          fSearchBar.getControl().append(String.valueOf(e.character));
          fSearchBar.getControl().setFocus();

          /* Consume the Event */
          e.doit = false;
        }

        /* Reset any Filter if set */
        else if (e.keyCode == SWT.ESC && fSearchBar.getControl().getText().length() != 0) {
          fSearchBar.setFilterText(""); //$NON-NLS-1$
          setSearchBarVisible(fAlwaysShowSearch);
          setFocus();
        }
      }
    });

    /* Hide SearchBar if search is done */
    fSearchBar.getControl().addModifyListener(new ModifyListener() {
      public void modifyText(ModifyEvent e) {

        /* Feature not Used, return */
        if (fAlwaysShowSearch)
          return;

        /* Search is Done */
        if (fSearchBar.getControl().getText().length() == 0) {
          setSearchBarVisible(false);
          setFocus();
        }
      }
    });
  }

  void setSearchBarVisible(boolean visible) {

    /* Return if no State Change */
    if (visible != ((GridData) fSeparator.getLayoutData()).exclude)
      return;

    /* Update LayoutData and layout Parent */
    ((GridData) fSeparator.getLayoutData()).exclude = !visible;
    ((GridData) fSearchBarContainer.getLayoutData()).exclude = !visible;
    fSearchBarContainer.getParent().layout();
  }

  private void hookViewMenu() {
    IMenuManager menuManager = fViewSite.getActionBars().getMenuManager();
    menuManager.setRemoveAllWhenShown(true);
    menuManager.addMenuListener(new IMenuListener() {
      public void menuAboutToShow(IMenuManager manager) {

        /* Manage Bookmark Sets */
        IAction manageSets = new Action(Messages.BookMarkExplorer_MANAGE_SETS) {
          @Override
          public void run() {
            ManageSetsDialog instance = ManageSetsDialog.getVisibleInstance();
            if (instance == null) {
              ManageSetsDialog dialog = new ManageSetsDialog(fViewSite.getShell(), fSelectedBookMarkSet);
              dialog.open();
            } else {
              instance.getShell().forceActive();
            }
          }
        };
        manager.add(manageSets);

        /* Available Bookmark Sets */
        manager.add(new Separator());
        for (final IFolder rootFolder : fRootFolders) {
          IAction selectBookMarkSet = new Action(rootFolder.getName(), IAction.AS_RADIO_BUTTON) {
            @Override
            public void run() {
              if (!fSelectedBookMarkSet.equals(rootFolder) && isChecked())
                changeSet(rootFolder);
            }
          };
          selectBookMarkSet.setImageDescriptor(OwlUI.BOOKMARK_SET);

          if (fSelectedBookMarkSet.equals(rootFolder))
            selectBookMarkSet.setChecked(true);

          manager.add(selectBookMarkSet);
        }

        /* Search Bar */
        manager.add(new Separator());
        MenuManager searchMenu = new MenuManager(Messages.BookMarkExplorer_FIND);
        manager.add(searchMenu);

        /* Search Bar - Always Show Bar */
        IAction alwaysShow = new Action(Messages.BookMarkExplorer_ALWAYS_SHOW, IAction.AS_CHECK_BOX) {
          @Override
          public void run() {
            fAlwaysShowSearch = !fAlwaysShowSearch;

            /* Only Update if the Filter is not Active */
            if (fSearchBar.getControl().getText().length() == 0)
              setSearchBarVisible(fAlwaysShowSearch);
          }
        };
        alwaysShow.setChecked(fAlwaysShowSearch);
        searchMenu.add(alwaysShow);

        /* Search Bar - Begin Search when Typing */
        IAction beginWhenTyping = new Action(Messages.BookMarkExplorer_BEGIN_WHEN_TYPING, IAction.AS_CHECK_BOX) {
          @Override
          public void run() {
            fBeginSearchOnTyping = !fBeginSearchOnTyping;
          }
        };
        beginWhenTyping.setChecked(fBeginSearchOnTyping);
        searchMenu.add(beginWhenTyping);

        /* Misc. Settings */
        manager.add(new Separator());
        IAction sortByName = new Action(Messages.BookMarkExplorer_SORT_BY_NAME, IAction.AS_CHECK_BOX) {
          @Override
          public void run() {
            fSortByName = !fSortByName;
            if (fSortByName)
              fBookMarkComparator.setType(BookMarkSorter.Type.SORT_BY_NAME);
            else
              fBookMarkComparator.setType(BookMarkSorter.Type.DEFAULT_SORTING);
            fViewer.refresh(false);

            /* Save directly to global scope */
            fGlobalPreferences.putBoolean(DefaultPreferences.BE_SORT_BY_NAME, fSortByName);
          }
        };
        sortByName.setChecked(fSortByName);
        manager.add(sortByName);

        IAction showFavicons = new Action(Messages.BookMarkExplorer_SHOW_FAVICONS, IAction.AS_CHECK_BOX) {
          @Override
          public void run() {
            fFaviconsEnabled = isChecked();

            fLabelProvider.setUseFavicons(fFaviconsEnabled);
            fViewer.getTree().setRedraw(false);
            try {
              fViewer.refresh(true);
            } finally {
              fViewer.getTree().setRedraw(true);
            }
          }
        };
        showFavicons.setChecked(fFaviconsEnabled);
        manager.add(showFavicons);

        /* Allow Contributions */
        manager.add(new Separator());

        IAction linkFeedView = new Action(Messages.BookMarkExplorer_LINKING, IAction.AS_CHECK_BOX) {
          @Override
          public void run() {
            fLinkingEnabled = isChecked();

            /* Link if enabled */
            if (fLinkingEnabled) {
              IEditorPart editor = fViewSite.getPage().getActiveEditor();
              if (editor != null)
                editorActivated(editor);
            }
          }
        };
        linkFeedView.setChecked(fLinkingEnabled);
        linkFeedView.setImageDescriptor(OwlUI.getImageDescriptor("icons/etool16/synced.gif")); //$NON-NLS-1$
        manager.add(linkFeedView);

        /* Allow Contributions */
        manager.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS));
      }
    });

    /* Dummy Entry to show Menu in View */
    menuManager.add(new Action("") {}); //$NON-NLS-1$
  }

  private void hookToolBar() {
    fToolBarManager = fViewSite.getActionBars().getToolBarManager();

    /* BookMark Filter */
    final IAction bookmarkFilter = new Action(Messages.BookMarkExplorer_FILTER_ELEMENTS, IAction.AS_DROP_DOWN_MENU) {
      @Override
      public void run() {

        /* Restore Default */
        if (fBookMarkFilter.getType() != BookMarkFilter.Type.SHOW_ALL)
          doFilter(BookMarkFilter.Type.SHOW_ALL);

        /* Toggle to Previous */
        else if (fLastFilterType != null)
          doFilter(fLastFilterType);

        /* Show Menu */
        else if (fToolBarManager instanceof ToolBarManager)
          OwlUI.positionDropDownMenu(this, (ToolBarManager) fToolBarManager);
      }

      @Override
      public ImageDescriptor getImageDescriptor() {
        if (fBookMarkFilter.getType() == BookMarkFilter.Type.SHOW_ALL)
          return OwlUI.FILTER;

        return OwlUI.getImageDescriptor("icons/etool16/filter_active.gif"); //$NON-NLS-1$
      }
    };
    bookmarkFilter.setId(FILTER_ACTION);

    bookmarkFilter.setMenuCreator(new ContextMenuCreator() {

      @Override
      public Menu createMenu(Control parent) {
        Menu menu = new Menu(parent);

        /* Filter: None */
        final MenuItem showAll = new MenuItem(menu, SWT.RADIO);
        showAll.setText(Messages.BookMarkExplorer_SHOW_ALL);
        showAll.setSelection(BookMarkFilter.Type.SHOW_ALL == fBookMarkFilter.getType());
        menu.setDefaultItem(showAll);
        showAll.addSelectionListener(new SelectionAdapter() {
          @Override
          public void widgetSelected(SelectionEvent e) {
            if (showAll.getSelection() && fBookMarkFilter.getType() != BookMarkFilter.Type.SHOW_ALL)
              doFilter(BookMarkFilter.Type.SHOW_ALL);
          }
        });

        /* Separator */
        new MenuItem(menu, SWT.SEPARATOR);

        /* Filter: New */
        final MenuItem showNew = new MenuItem(menu, SWT.RADIO);
        showNew.setText(Messages.BookMarkExplorer_SHOW_NEW);
        showNew.setSelection(BookMarkFilter.Type.SHOW_NEW == fBookMarkFilter.getType());
        showNew.addSelectionListener(new SelectionAdapter() {

          @Override
          public void widgetSelected(SelectionEvent e) {
            if (showNew.getSelection() && fBookMarkFilter.getType() != BookMarkFilter.Type.SHOW_NEW)
              doFilter(BookMarkFilter.Type.SHOW_NEW);
          }
        });

        /* Filter: Unread */
        final MenuItem showUnread = new MenuItem(menu, SWT.RADIO);
        showUnread.setText(Messages.BookMarkExplorer_SHOW_UNREAD);
        showUnread.setSelection(BookMarkFilter.Type.SHOW_UNREAD == fBookMarkFilter.getType());
        showUnread.addSelectionListener(new SelectionAdapter() {

          @Override
          public void widgetSelected(SelectionEvent e) {
            if (showUnread.getSelection() && fBookMarkFilter.getType() != BookMarkFilter.Type.SHOW_UNREAD)
              doFilter(BookMarkFilter.Type.SHOW_UNREAD);
          }
        });

        /* Filter: Sticky */
        final MenuItem showSticky = new MenuItem(menu, SWT.RADIO);
        showSticky.setText(Messages.BookMarkExplorer_SHOW_STICKY);
        showSticky.setSelection(BookMarkFilter.Type.SHOW_STICKY == fBookMarkFilter.getType());
        showSticky.addSelectionListener(new SelectionAdapter() {

          @Override
          public void widgetSelected(SelectionEvent e) {
            if (showSticky.getSelection() && fBookMarkFilter.getType() != BookMarkFilter.Type.SHOW_STICKY)
              doFilter(BookMarkFilter.Type.SHOW_STICKY);
          }
        });

        /* Separator */
        new MenuItem(menu, SWT.SEPARATOR);

        /* Filter: Erroneous */
        final MenuItem showErroneous = new MenuItem(menu, SWT.RADIO);
        showErroneous.setText(Messages.BookMarkExplorer_SHOW_ERROR);
        showErroneous.setSelection(BookMarkFilter.Type.SHOW_ERRONEOUS == fBookMarkFilter.getType());
        showErroneous.addSelectionListener(new SelectionAdapter() {
          @Override
          public void widgetSelected(SelectionEvent e) {
            if (showErroneous.getSelection() && fBookMarkFilter.getType() != BookMarkFilter.Type.SHOW_ERRONEOUS)
              doFilter(BookMarkFilter.Type.SHOW_ERRONEOUS);
          }
        });

        /* Filter: Never Visited */
        final MenuItem showNeverVisited = new MenuItem(menu, SWT.RADIO);
        showNeverVisited.setText(Messages.BookMarkExplorer_SHOW_NEVER_VISITED);
        showNeverVisited.setSelection(BookMarkFilter.Type.SHOW_NEVER_VISITED == fBookMarkFilter.getType());
        showNeverVisited.addSelectionListener(new SelectionAdapter() {
          @Override
          public void widgetSelected(SelectionEvent e) {
            if (showNeverVisited.getSelection() && fBookMarkFilter.getType() != BookMarkFilter.Type.SHOW_NEVER_VISITED)
              doFilter(BookMarkFilter.Type.SHOW_NEVER_VISITED);
          }
        });

        return menu;
      }
    });

    fToolBarManager.add(bookmarkFilter);

    /* Bookmark Group */
    fToolBarManager.add(new Separator());
    final IAction bookmarkGroup = new Action(Messages.BookMarkExplorer_GROUP_ELEMENTS, IAction.AS_DROP_DOWN_MENU) {
      @Override
      public void run() {

        /* Restore Default */
        if (fBookMarkGrouping.getType() != BookMarkGrouping.Type.NO_GROUPING)
          doGrouping(BookMarkGrouping.Type.NO_GROUPING);

        /* Toggle to previous */
        else if (fLastGroupType != null)
          doGrouping(fLastGroupType);

        /* Show Menu */
        else if (fToolBarManager instanceof ToolBarManager)
          OwlUI.positionDropDownMenu(this, (ToolBarManager) fToolBarManager);
      }

      @Override
      public ImageDescriptor getImageDescriptor() {
        if (fBookMarkGrouping.getType() == BookMarkGrouping.Type.NO_GROUPING)
          return OwlUI.getImageDescriptor("icons/etool16/group.gif"); //$NON-NLS-1$

        return OwlUI.getImageDescriptor("icons/etool16/group_active.gif"); //$NON-NLS-1$
      }
    };
    bookmarkGroup.setId(GROUP_ACTION);

    bookmarkGroup.setMenuCreator(new ContextMenuCreator() {

      @Override
      public Menu createMenu(Control parent) {
        Menu menu = new Menu(parent);

        /* Group: None */
        final MenuItem noGrouping = new MenuItem(menu, SWT.RADIO);
        noGrouping.setText(Messages.BookMarkExplorer_NO_GROUPING);
        noGrouping.setSelection(BookMarkGrouping.Type.NO_GROUPING == fBookMarkGrouping.getType());
        menu.setDefaultItem(noGrouping);
        noGrouping.addSelectionListener(new SelectionAdapter() {
          @Override
          public void widgetSelected(SelectionEvent e) {
            if (noGrouping.getSelection() && fBookMarkGrouping.getType() != BookMarkGrouping.Type.NO_GROUPING)
              doGrouping(BookMarkGrouping.Type.NO_GROUPING);
          }
        });

        /* Separator */
        new MenuItem(menu, SWT.SEPARATOR);

        /* Group: By Type */
        final MenuItem groupByType = new MenuItem(menu, SWT.RADIO);
        groupByType.setText(Messages.BookMarkExplorer_GROUP_BY_TYPE);
        groupByType.setSelection(BookMarkGrouping.Type.GROUP_BY_TYPE == fBookMarkGrouping.getType());
        groupByType.addSelectionListener(new SelectionAdapter() {
          @Override
          public void widgetSelected(SelectionEvent e) {
            if (groupByType.getSelection() && fBookMarkGrouping.getType() != BookMarkGrouping.Type.GROUP_BY_TYPE)
              doGrouping(BookMarkGrouping.Type.GROUP_BY_TYPE);
          }
        });

        /* Group: By State */
        final MenuItem groupByState = new MenuItem(menu, SWT.RADIO);
        groupByState.setText(Messages.BookMarkExplorer_GROUP_BY_STATE);
        groupByState.setSelection(BookMarkGrouping.Type.GROUP_BY_STATE == fBookMarkGrouping.getType());
        groupByState.addSelectionListener(new SelectionAdapter() {
          @Override
          public void widgetSelected(SelectionEvent e) {
            if (groupByState.getSelection() && fBookMarkGrouping.getType() != BookMarkGrouping.Type.GROUP_BY_STATE)
              doGrouping(BookMarkGrouping.Type.GROUP_BY_STATE);
          }
        });

        /* Separator */
        new MenuItem(menu, SWT.SEPARATOR);

        /* Group: By Last Visit */
        final MenuItem groupByLastVisit = new MenuItem(menu, SWT.RADIO);
        groupByLastVisit.setText(Messages.BookMarkExplorer_GROUP_BY_LAST_VISIT);
        groupByLastVisit.setSelection(BookMarkGrouping.Type.GROUP_BY_LAST_VISIT == fBookMarkGrouping.getType());
        groupByLastVisit.addSelectionListener(new SelectionAdapter() {
          @Override
          public void widgetSelected(SelectionEvent e) {
            if (groupByLastVisit.getSelection() && fBookMarkGrouping.getType() != BookMarkGrouping.Type.GROUP_BY_LAST_VISIT)
              doGrouping(BookMarkGrouping.Type.GROUP_BY_LAST_VISIT);
          }
        });

        /* Group: By Popularity */
        final MenuItem groupByPopularity = new MenuItem(menu, SWT.RADIO);
        groupByPopularity.setText(Messages.BookMarkExplorer_GROUP_BY_POPULARITY);
        groupByPopularity.setSelection(BookMarkGrouping.Type.GROUP_BY_POPULARITY == fBookMarkGrouping.getType());
        groupByPopularity.addSelectionListener(new SelectionAdapter() {
          @Override
          public void widgetSelected(SelectionEvent e) {
            if (groupByPopularity.getSelection() && fBookMarkGrouping.getType() != BookMarkGrouping.Type.GROUP_BY_POPULARITY)
              doGrouping(BookMarkGrouping.Type.GROUP_BY_POPULARITY);
          }
        });

        return menu;
      }
    });

    fToolBarManager.add(bookmarkGroup);

    /* Collapse All */
    fToolBarManager.add(new Separator());
    IAction collapseAll = new Action(Messages.BookMarkExplorer_COLLAPSE_ALL) {
      @Override
      public void run() {
        fViewer.collapseAll();
        fExpandedNodes.clear();
      }
    };
    collapseAll.setImageDescriptor(OwlUI.getImageDescriptor("icons/etool16/collapseall.gif")); //$NON-NLS-1$
    fToolBarManager.add(collapseAll);

    /* BookmarkSet Navigation - TODO Consider showing dynamically */
    IAction previousSet = new Action(Messages.BookMarkExplorer_PREVIOUS_SET) {
      @Override
      public void run() {
        int index = getIndexOfRootFolder(fSelectedBookMarkSet);
        changeSet(getRootFolderAt(index - 1));
      }

      @Override
      public boolean isEnabled() {
        int index = getIndexOfRootFolder(fSelectedBookMarkSet);
        return index > 0 && fRootFolders.size() > 1;
      }
    };
    previousSet.setId(PREVIOUS_SET_ACTION);
    previousSet.setImageDescriptor(OwlUI.getImageDescriptor("icons/etool16/backward.gif")); //$NON-NLS-1$
    previousSet.setDisabledImageDescriptor(OwlUI.getImageDescriptor("icons/dtool16/backward.gif")); //$NON-NLS-1$
    fToolBarManager.add(previousSet);

    IAction nextSet = new Action(Messages.BookMarkExplorer_NEXT_SET) {
      @Override
      public void run() {
        int index = getIndexOfRootFolder(fSelectedBookMarkSet);
        changeSet(getRootFolderAt(index + 1));
      }

      @Override
      public boolean isEnabled() {
        int index = getIndexOfRootFolder(fSelectedBookMarkSet);
        return index < (fRootFolders.size() - 1) && fRootFolders.size() > 1;
      }
    };
    nextSet.setId(NEXT_SET_ACTION);
    nextSet.setImageDescriptor(OwlUI.getImageDescriptor("icons/etool16/forward.gif")); //$NON-NLS-1$
    nextSet.setDisabledImageDescriptor(OwlUI.getImageDescriptor("icons/dtool16/forward.gif")); //$NON-NLS-1$
    fToolBarManager.add(nextSet);

    /* Allow Contributions */
    fToolBarManager.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS));
  }

  private void doFilter(BookMarkFilter.Type type) {

    /* Remember Selection */
    if (type != BookMarkFilter.Type.SHOW_ALL)
      fLastFilterType = type;
    else if (fBookMarkFilter.getType() != BookMarkFilter.Type.SHOW_ALL)
      fLastFilterType = fBookMarkFilter.getType();

    /* Change Filter Type */
    fBookMarkFilter.setType(type);
    fViewer.refresh(false);

    /* Restore Expanded Elements */
    restoreExpandedElements();

    /* Update Image */
    fToolBarManager.find(FILTER_ACTION).update(IAction.IMAGE);
  }

  private void doGrouping(BookMarkGrouping.Type type) {

    /* Remember Selection */
    if (type != BookMarkGrouping.Type.NO_GROUPING)
      fLastGroupType = type;
    else if (fBookMarkGrouping.getType() != BookMarkGrouping.Type.NO_GROUPING)
      fLastGroupType = fBookMarkGrouping.getType();

    /* Temporary change Sorter to reflect grouping */
    if (!fSortByName) {
      if (type.equals(BookMarkGrouping.Type.NO_GROUPING))
        fBookMarkComparator.setType(BookMarkSorter.Type.DEFAULT_SORTING);
      else if (type.equals(BookMarkGrouping.Type.GROUP_BY_LAST_VISIT))
        fBookMarkComparator.setType(BookMarkSorter.Type.SORT_BY_LAST_VISIT_DATE);
      else if (type.equals(BookMarkGrouping.Type.GROUP_BY_POPULARITY))
        fBookMarkComparator.setType(BookMarkSorter.Type.SORT_BY_POPULARITY);
    }

    /* Refresh w/o updating Labels */
    fBookMarkGrouping.setType(type);
    fViewer.refresh(false);

    /* Restore Sorter */
    fBookMarkComparator.setType(fSortByName ? BookMarkSorter.Type.SORT_BY_NAME : BookMarkSorter.Type.DEFAULT_SORTING);

    /* Restore expanded Elements */
    restoreExpandedElements();

    /* Update Image */
    fToolBarManager.find(GROUP_ACTION).update(IAction.IMAGE);
  }

  private void hookContextualMenu() {
    MenuManager manager = new MenuManager();
    manager.setRemoveAllWhenShown(true);
    manager.addMenuListener(new IMenuListener() {
      public void menuAboutToShow(IMenuManager manager) {

        /* New Menu */
        MenuManager newMenu = new MenuManager(Messages.BookMarkExplorer_NEW);
        manager.add(newMenu);

        /* New BookMark */
        Action newBookmarkAction = new Action(Messages.BookMarkExplorer_BOOKMARK) {
          @Override
          public void run() {
            IStructuredSelection selection = (IStructuredSelection) fViewer.getSelection();
            IFolder parent = getParent(selection);
            IMark position = (IMark) ((selection.getFirstElement() instanceof IMark) ? selection.getFirstElement() : null);
            new NewBookMarkAction(fViewSite.getShell(), parent, position).run(null);
          }

          @Override
          public ImageDescriptor getImageDescriptor() {
            return OwlUI.BOOKMARK;
          }
        };
        newBookmarkAction.setId("org.rssowl.ui.actions.NewBookMark"); //$NON-NLS-1$
        newBookmarkAction.setActionDefinitionId("org.rssowl.ui.actions.NewBookMark"); //$NON-NLS-1$
        newMenu.add(newBookmarkAction);

        /* New NewsBin */
        Action newNewsBinAction = new Action(Messages.BookMarkExplorer_NEWSBIN) {
          @Override
          public void run() {
            IStructuredSelection selection = (IStructuredSelection) fViewer.getSelection();
            IFolder parent = getParent(selection);
            IMark position = (IMark) ((selection.getFirstElement() instanceof IMark) ? selection.getFirstElement() : null);
            new NewNewsBinAction(fViewSite.getShell(), parent, position).run(null);
          }

          @Override
          public ImageDescriptor getImageDescriptor() {
            return OwlUI.NEWSBIN;
          }
        };
        newNewsBinAction.setId("org.rssowl.ui.actions.NewNewsBin"); //$NON-NLS-1$
        newNewsBinAction.setActionDefinitionId("org.rssowl.ui.actions.NewNewsBin"); //$NON-NLS-1$
        newMenu.add(newNewsBinAction);

        /* New Saved Search */
        Action newSavedSearchAction = new Action(Messages.BookMarkExplorer_SAVED_SEARCH) {
          @Override
          public void run() {
            IStructuredSelection selection = (IStructuredSelection) fViewer.getSelection();
            IFolder parent = getParent(selection);
            IMark position = (IMark) ((selection.getFirstElement() instanceof IMark) ? selection.getFirstElement() : null);
            new NewSearchMarkAction(fViewSite.getShell(), parent, position).run(null);
          }

          @Override
          public ImageDescriptor getImageDescriptor() {
            return OwlUI.SEARCHMARK;
          }
        };
        newSavedSearchAction.setId("org.rssowl.ui.actions.NewSearchMark"); //$NON-NLS-1$
        newSavedSearchAction.setActionDefinitionId("org.rssowl.ui.actions.NewSearchMark"); //$NON-NLS-1$
        newMenu.add(newSavedSearchAction);

        /* New Folder */
        newMenu.add(new Separator());
        Action newFolderAction = new Action(Messages.BookMarkExplorer_FOLDER) {
          @Override
          public void run() {
            IStructuredSelection selection = (IStructuredSelection) fViewer.getSelection();
            IFolder parent = getParent(selection);
            IMark position = (IMark) ((selection.getFirstElement() instanceof IMark) ? selection.getFirstElement() : null);
            new NewFolderAction(fViewSite.getShell(), parent, position).run(null);
          }

          @Override
          public ImageDescriptor getImageDescriptor() {
            return OwlUI.FOLDER;
          }
        };
        newFolderAction.setId("org.rssowl.ui.actions.NewFolder"); //$NON-NLS-1$
        newFolderAction.setActionDefinitionId("org.rssowl.ui.actions.NewFolder"); //$NON-NLS-1$
        newMenu.add(newFolderAction);

        manager.add(new GroupMarker(IWorkbenchActionConstants.NEW_EXT));

        /* Mark Read */
        manager.add(new Separator(OwlUI.M_MARK));

        /* Search News */
        manager.add(new Separator());
        manager.add(new SearchInTypeAction(fViewSite.getWorkbenchWindow(), fViewer));
        manager.add(new GroupMarker(IWorkbenchActionConstants.FIND_EXT));

        /* Share */
        final IStructuredSelection selection = (IStructuredSelection) fViewer.getSelection();
        if (getBookMark(selection) != null) {
          manager.add(new Separator("share")); //$NON-NLS-1$
          MenuManager shareMenu = new MenuManager(Messages.BookMarkExplorer_SHARING, OwlUI.SHARE, "sharebookmark"); //$NON-NLS-1$
          manager.add(shareMenu);

          List<ShareProvider> providers = Controller.getDefault().getShareProviders();
          for (final ShareProvider provider : providers) {
            if (provider.isEnabled()) {
              shareMenu.add(new Action(provider.getName()) {
                @Override
                public void run() {
                  if (SendLinkAction.ID.equals(provider.getId())) {
                    IActionDelegate action = new SendLinkAction();
                    action.selectionChanged(null, selection);
                    action.run(null);
                  } else {
                    IBookMark bookmark = getBookMark(selection);
                    if (bookmark != null) {
                      String shareLink = provider.toShareUrl(bookmark);
                      new OpenInBrowserAction(new StructuredSelection(shareLink)).run();
                    }
                  }
                };

                @Override
                public ImageDescriptor getImageDescriptor() {
                  if (StringUtils.isSet(provider.getIconPath()))
                    return OwlUI.getImageDescriptor(provider.getPluginId(), provider.getIconPath());

                  return super.getImageDescriptor();
                };

                @Override
                public boolean isEnabled() {
                  return !selection.isEmpty();
                };

                @Override
                public String getActionDefinitionId() {
                  return SendLinkAction.ID.equals(provider.getId()) ? SendLinkAction.ID : super.getActionDefinitionId();
                }

                @Override
                public String getId() {
                  return SendLinkAction.ID.equals(provider.getId()) ? SendLinkAction.ID : super.getId();
                }
              });
            }
          }

          /* Configure Providers */
          shareMenu.add(new Separator());
          shareMenu.add(new Action(Messages.BookMarkExplorer_CONFIGURE) {
            @Override
            public void run() {
              PreferencesUtil.createPreferenceDialogOn(fViewer.getTree().getShell(), SharingPreferencesPage.ID, null, null).open();
            };
          });
        }

        manager.add(new Separator("copy")); //$NON-NLS-1$
        manager.add(new GroupMarker("edit")); //$NON-NLS-1$

        /* Allow Contributions */
        manager.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS));
      }
    });

    /* Create and Register with Workbench */
    Menu menu = manager.createContextMenu(fViewer.getControl());
    fViewer.getControl().setMenu(menu);
    fViewSite.registerContextMenu(manager, fViewer);
  }

  private IBookMark getBookMark(IStructuredSelection selection) {
    List<?> list = selection.toList();
    for (Object object : list) {
      if (object instanceof IBookMark)
        return (IBookMark) object;
    }

    return null;
  }

  private void registerListeners() {

    /* Listen for Events on Root-Folders */
    fFolderListener = new FolderAdapter() {

      @Override
      public void entitiesAdded(final Set<FolderEvent> events) {
        JobRunner.runInUIThread(fViewer.getControl(), new Runnable() {
          public void run() {
            for (FolderEvent event : events) {
              if (event.getEntity().getParent() == null) {
                fRootFolders.add(event.getEntity());

                /* Show this Folder in the Explorer */
                changeSet(event.getEntity());
              }
            }
          }
        });
      }

      @Override
      public void entitiesDeleted(final Set<FolderEvent> events) {
        JobRunner.runInUIThread(fViewer.getControl(), new Runnable() {
          public void run() {
            for (FolderEvent event : events) {
              IFolder deletedFolder = event.getEntity();
              IFolder parentFolder = event.getEntity().getParent();
              if (parentFolder == null) {
                int index = getIndexOfRootFolder(deletedFolder);
                fRootFolders.remove(event.getEntity());

                /* In case this Bookmark set is currently showing in the Explorer */
                if (fSelectedBookMarkSet.equals(deletedFolder)) {
                  if (fRootFolders.size() > index)
                    changeSet(getRootFolderAt(index));
                  else
                    changeSet(getRootFolderAt(index - 1));
                }

                /* Otherwise make sure to update Nav-Buttons */
                else {
                  fViewSite.getActionBars().getToolBarManager().find(PREVIOUS_SET_ACTION).update(IAction.ENABLED);
                  fViewSite.getActionBars().getToolBarManager().find(NEXT_SET_ACTION).update(IAction.ENABLED);
                }
              }
            }
          }
        });
      }
    };
    DynamicDAO.addEntityListener(IFolder.class, fFolderListener);

    /* Listen for Editors activated for the linking Feature */
    fPartListener = new IPartListener2() {
      public void partActivated(IWorkbenchPartReference ref) {
        if (ref.getPart(true) instanceof IEditorPart) {

          /* Workaround for Bug 573 */
          JobRunner.runInUIThread(50, fViewer.getTree(), new Runnable() {
            public void run() {
              editorActivated(fViewSite.getPage().getActiveEditor());
            }
          });
        }
      }

      public void partBroughtToTop(IWorkbenchPartReference ref) {
        if (ref.getPart(true) == BookMarkExplorer.this)
          editorActivated(fViewSite.getPage().getActiveEditor());
      }

      public void partOpened(IWorkbenchPartReference ref) {
        if (ref.getPart(true) == BookMarkExplorer.this)
          editorActivated(fViewSite.getPage().getActiveEditor());
      }

      public void partVisible(IWorkbenchPartReference ref) {
        if (ref.getPart(true) == BookMarkExplorer.this)
          editorActivated(fViewSite.getPage().getActiveEditor());
      }

      public void partClosed(IWorkbenchPartReference ref) {}

      public void partDeactivated(IWorkbenchPartReference ref) {}

      public void partHidden(IWorkbenchPartReference ref) {}

      public void partInputChanged(IWorkbenchPartReference ref) {
        if (ref.getPart(true) instanceof IEditorPart) {

          /* Workaround for Bug 1126 */
          JobRunner.runInUIThread(50, fViewer.getTree(), new Runnable() {
            public void run() {
              editorActivated(fViewSite.getPage().getActiveEditor());
            }
          });
        }
      }
    };

    fViewSite.getPage().addPartListener(fPartListener);

    /* Refresh Viewer when Sticky Color Changes */
    fPropertyChangeListener = new IPropertyChangeListener() {
      public void propertyChange(PropertyChangeEvent event) {
        if (fViewer.getControl().isDisposed())
          return;

        if (OwlUI.STICKY_BG_COLOR_ID.equals(event.getProperty())) {
          fLabelProvider.updateResources();
          fViewer.refresh(true);
        }
      }
    };
    PlatformUI.getWorkbench().getThemeManager().addPropertyChangeListener(fPropertyChangeListener);
  }

  private void unregisterListeners() {
    DynamicDAO.removeEntityListener(IFolder.class, fFolderListener);
    fViewSite.getPage().removePartListener(fPartListener);
    PlatformUI.getWorkbench().getThemeManager().removePropertyChangeListener(fPropertyChangeListener);
  }

  private void hookGlobalActions() {

    /* Select All */
    fViewSite.getActionBars().setGlobalActionHandler(ActionFactory.SELECT_ALL.getId(), new Action() {
      @Override
      public void run() {
        Control focusControl = fViewer.getControl().getDisplay().getFocusControl();

        /* Select All in Text Widget */
        if (focusControl instanceof Text) {
          ((Text) focusControl).selectAll();
        }

        /* Select All in Tree */
        else {
          ((Tree) fViewer.getControl()).selectAll();
          fViewer.setSelection(fViewer.getSelection());
        }
      }
    });

    /* Delete */
    fViewSite.getActionBars().setGlobalActionHandler(ActionFactory.DELETE.getId(), new Action() {
      @Override
      public void run() {
        fViewer.getControl().getParent().setRedraw(false);
        try {
          new DeleteTypesAction(fViewer.getControl().getShell(), (IStructuredSelection) fViewer.getSelection()).run();
        } finally {
          fViewer.getControl().getParent().setRedraw(true);
        }
      }
    });

    /* Reload */
    fViewSite.getActionBars().setGlobalActionHandler(RetargetActions.RELOAD, new Action() {
      @Override
      public void run() {
        new ReloadTypesAction((IStructuredSelection) fViewer.getSelection(), fViewSite.getShell()).run();
      }
    });

    /* Cut */
    fViewSite.getActionBars().setGlobalActionHandler(ActionFactory.CUT.getId(), new Action() {
      @Override
      public void run() {
        Control focusControl = fViewer.getControl().getDisplay().getFocusControl();

        /* Cut in Text Widget */
        if (focusControl instanceof Text)
          ((Text) focusControl).cut();
      }
    });

    /* Copy */
    fViewSite.getActionBars().setGlobalActionHandler(ActionFactory.COPY.getId(), new Action() {
      @Override
      public void run() {
        Control focusControl = fViewer.getControl().getDisplay().getFocusControl();

        /* Copy in Text Widget */
        if (focusControl instanceof Text)
          ((Text) focusControl).copy();
      }
    });

    /* Paste */
    fViewSite.getActionBars().setGlobalActionHandler(ActionFactory.PASTE.getId(), new Action() {
      @Override
      public void run() {
        Control focusControl = fViewer.getControl().getDisplay().getFocusControl();

        /* Paste in Text Widget */
        if (focusControl instanceof Text)
          ((Text) focusControl).paste();
      }
    });

    /* Undo (Eclipse Integration) */
    fViewSite.getActionBars().setGlobalActionHandler(ActionFactory.UNDO.getId(), new Action() {
      @Override
      public void run() {
        UndoStack.getInstance().undo();
      }
    });

    /* Redo (Eclipse Integration) */
    fViewSite.getActionBars().setGlobalActionHandler(ActionFactory.REDO.getId(), new Action() {
      @Override
      public void run() {
        UndoStack.getInstance().redo();
      }
    });

    /* Find (Eclipse Integration) */
    fViewSite.getActionBars().setGlobalActionHandler(ActionFactory.FIND.getId(), new FindAction());

    /* Properties */
    fViewSite.getActionBars().setGlobalActionHandler(ActionFactory.PROPERTIES.getId(), new EntityPropertyDialogAction(fViewSite, fViewer));

    /* Disable some Edit-Actions at first */
    fViewSite.getActionBars().getGlobalActionHandler(ActionFactory.CUT.getId()).setEnabled(false);
    fViewSite.getActionBars().getGlobalActionHandler(ActionFactory.COPY.getId()).setEnabled(false);
    fViewSite.getActionBars().getGlobalActionHandler(ActionFactory.PASTE.getId()).setEnabled(false);
  }

  /**
   * The user performed the "Find" action.
   */
  public void find() {
    setSearchBarVisible(true);
    fSearchBar.getControl().setFocus();
  }

  /*
   * @see org.eclipse.ui.part.ViewPart#init(org.eclipse.ui.IViewSite)
   */
  @Override
  public void init(IViewSite site) throws PartInitException {
    super.init(site);
    fViewSite = site;
    fGlobalPreferences = Owl.getPreferenceService().getGlobalScope();
    fPrefDAO = DynamicDAO.getDAO(IPreferenceDAO.class);
    fExpandedNodes = new ArrayList<Long>();

    /* Sort Root-Folders by ID */
    fRootFolders = CoreUtils.loadRootFolders();

    /* Load Settings */
    loadState();
  }

  @Override
  @SuppressWarnings("unchecked")
  public Object getAdapter(Class adapter) {
    if (ISelectionProvider.class.equals(adapter))
      return fViewer;

    if (IInputProvider.class.equals(adapter))
      return fViewer.getInput();

    return super.getAdapter(adapter);
  }

  /*
   * @see org.eclipse.ui.part.WorkbenchPart#setFocus()
   */
  @Override
  public void setFocus() {
    fViewer.getControl().setFocus();
  }

  /*
   * @see org.eclipse.ui.part.WorkbenchPart#dispose()
   */
  @Override
  public void dispose() {
    super.dispose();
    unregisterListeners();
    saveState();
  }

  /**
   * Navigate to the next/previous read or unread Feed respecting the Marks that
   * are displayed in the Tree-Viewer.
   *
   * @param newsScoped If <code>TRUE</code>, the navigation looks for News and
   * for Feeds if <code>FALSE</code>.
   * @param next If <code>TRUE</code>, move to the next item, or previous if
   * <code>FALSE</code>.
   * @param unread If <code>TRUE</code>, only move to unread items, or ignore if
   * <code>FALSE</code>.
   * @return Returns <code>TRUE</code> in case navigation found a valid item, or
   * <code>FALSE</code> otherwise.
   */
  public boolean navigate(boolean newsScoped, boolean next, boolean unread) {
    Tree explorerTree = fViewer.getTree();

    /* Nothing to Navigate to */
    if (explorerTree.isDisposed())
      return false;

    ITreeNode targetNode = null;

    /* 1.) Navigate in opened Tree */
    targetNode = navigateInTree(explorerTree, next, unread);

    /* 2.) Navigate in BookMark-Sets */
    if (targetNode == null)
      targetNode = navigateInSets(next, unread);

    /* 3.) Finally, wrap in visible Tree if next */
    if (targetNode == null && next) {
      ITreeNode startingNode = new WidgetTreeNode(fViewer.getTree(), fViewer);
      targetNode = navigate(startingNode, next, unread);
    }

    /* Perform navigation if Node was found */
    if (targetNode != null) {
      performNavigation(targetNode, newsScoped, unread);
      return true;
    }

    return false;
  }

  private void performNavigation(ITreeNode targetNode, boolean newsScoped, boolean unread) {
    INewsMark mark = (INewsMark) targetNode.getData();

    /* Set Selection to Mark */
    IStructuredSelection selection = new StructuredSelection(mark);
    fViewer.setSelection(selection);

    /* Open in FeedView */
    PerformAfterInputSet perform = null;
    if (newsScoped && unread)
      perform = PerformAfterInputSet.SELECT_UNREAD_NEWS;
    else if (newsScoped)
      perform = PerformAfterInputSet.SELECT_FIRST_NEWS;

    OwlUI.openInFeedView(fViewSite.getPage(), selection, true, false, perform);
  }

  private ITreeNode navigateInTree(Tree tree, boolean next, boolean unread) {
    ITreeNode resultingNode = null;

    /* Selection is Present */
    if (tree.getSelectionCount() > 0) {

      /* Try navigating from Selection */
      ITreeNode startingNode = new WidgetTreeNode(tree.getSelection()[0], fViewer);
      resultingNode = navigate(startingNode, next, unread);
      if (resultingNode != null)
        return resultingNode;
    }

    /* No Selection is Present */
    else {
      ITreeNode startingNode = new WidgetTreeNode(tree, fViewer);
      resultingNode = navigate(startingNode, next, unread);
      if (resultingNode != null)
        return resultingNode;
    }

    return resultingNode;
  }

  private ITreeNode navigateInSets(boolean next, boolean unread) {
    ITreeNode targetNode = null;

    /* Index of current visible Set */
    int index = getIndexOfRootFolder(fSelectedBookMarkSet);

    /* Look in next Sets */
    if (next) {

      /* Sets to the right */
      for (int i = index + 1; i < fRootFolders.size(); i++) {
        targetNode = navigateInSet(getRootFolderAt(i), true, unread);
        if (targetNode != null)
          return targetNode;
      }

      /* Sets to the left */
      for (int i = 0; i < index; i++) {
        targetNode = navigateInSet(getRootFolderAt(i), true, unread);
        if (targetNode != null)
          return targetNode;
      }
    }

    /* Look in previous Sets */
    else {

      /* Sets to the left */
      for (int i = index - 1; i >= 0; i--) {
        targetNode = navigateInSet(getRootFolderAt(i), true, unread);
        if (targetNode != null)
          return targetNode;
      }

      /* Sets to the right */
      for (int i = fRootFolders.size() - 1; i > index; i--) {
        targetNode = navigateInSet(getRootFolderAt(i), true, unread);
        if (targetNode != null)
          return targetNode;
      }
    }

    return targetNode;
  }

  private ITreeNode navigateInSet(IFolder set, boolean next, boolean unread) {
    ITreeNode node = new ModelTreeNode(set);
    ITreeNode targetNode = navigate(node, next, unread);
    if (targetNode != null) {
      changeSet(set);
      return targetNode;
    }

    return null;
  }

  private ITreeNode navigate(ITreeNode startingNode, boolean next, final boolean unread) {

    /* Create Traverse-Helper */
    TreeTraversal traverse = new TreeTraversal(startingNode) {
      @Override
      public boolean select(ITreeNode node) {
        return isValidNavigation(node, unread);
      }
    };

    /* Retrieve and select new Target Node */
    ITreeNode targetNode = (next ? traverse.nextNode() : traverse.previousNode());

    return targetNode;
  }

  private boolean isValidNavigation(ITreeNode node, boolean unread) {
    Object data = node.getData();

    /* Check for Unread news if required */
    if (data instanceof INewsMark) {
      INewsMark newsmark = (INewsMark) data;
      if (unread && newsmark.getNewsCount(EnumSet.of(INews.State.NEW, INews.State.UNREAD, INews.State.UPDATED)) == 0)
        return false;
    }

    /* Folders and Entity Groups are no valid navigation nodes */
    else if (data instanceof IFolder || data instanceof EntityGroup)
      return false;

    return true;
  }

  /**
   * Save all Settings of the Explorer immediately.
   */
  public void saveState() {

    /* Expanded Elements */
    saveExpandedElements();

    /* Selection */
    if (fLastSelection != null && !fLastSelection.isEmpty()) {
      Object element = fLastSelection.getFirstElement();
      if (element instanceof IFolderChild)
        fGlobalPreferences.putLong(PREF_SELECTED_FOLDER_CHILD, ((IFolderChild) element).getId());
      else
        fGlobalPreferences.delete(PREF_SELECTED_FOLDER_CHILD);
    } else
      fGlobalPreferences.delete(PREF_SELECTED_FOLDER_CHILD);

    /* Misc. Settings */
    if (!fBlockSaveState) {
      fGlobalPreferences.putBoolean(DefaultPreferences.BE_BEGIN_SEARCH_ON_TYPING, fBeginSearchOnTyping);
      fGlobalPreferences.putBoolean(DefaultPreferences.BE_ALWAYS_SHOW_SEARCH, fAlwaysShowSearch);
      fGlobalPreferences.putBoolean(DefaultPreferences.BE_SORT_BY_NAME, fSortByName);
      fGlobalPreferences.putBoolean(DefaultPreferences.BE_ENABLE_LINKING, fLinkingEnabled);
      fGlobalPreferences.putBoolean(DefaultPreferences.BE_DISABLE_FAVICONS, !fFaviconsEnabled);
      fGlobalPreferences.putInteger(DefaultPreferences.BE_FILTER_TYPE, fBookMarkFilter.getType().ordinal());
      fGlobalPreferences.putInteger(DefaultPreferences.BE_GROUP_TYPE, fBookMarkGrouping.getType().ordinal());
    }
  }

  private void saveExpandedElements() {
    int i = 0;
    long elements[] = new long[fExpandedNodes.size()];
    for (Object element : fExpandedNodes) {
      elements[i] = (Long) element;
      i++;
    }
    /* Add the ID of the current selected Set to make it Unique */
    String key = PREF_EXPANDED_NODES + fSelectedBookMarkSet.getId();

    IPreference pref = fPrefDAO.loadOrCreate(key);
    pref.putLongs(elements);
    fPrefDAO.save(pref);
  }

  private void loadState() {

    /* Misc. Settings */
    fBeginSearchOnTyping = fGlobalPreferences.getBoolean(DefaultPreferences.BE_BEGIN_SEARCH_ON_TYPING);
    fAlwaysShowSearch = fGlobalPreferences.getBoolean(DefaultPreferences.BE_ALWAYS_SHOW_SEARCH);
    fSortByName = fGlobalPreferences.getBoolean(DefaultPreferences.BE_SORT_BY_NAME);
    fLinkingEnabled = fGlobalPreferences.getBoolean(DefaultPreferences.BE_ENABLE_LINKING);
    fFaviconsEnabled = !fGlobalPreferences.getBoolean(DefaultPreferences.BE_DISABLE_FAVICONS);
    fFilterType = BookMarkFilter.Type.values()[fGlobalPreferences.getInteger(DefaultPreferences.BE_FILTER_TYPE)];
    fGroupingType = BookMarkGrouping.Type.values()[fGlobalPreferences.getInteger(DefaultPreferences.BE_GROUP_TYPE)];

    String selectedBookMarkSetPref = getSelectedBookMarkSetPref(fViewSite.getWorkbenchWindow());
    IPreference pref = fPrefDAO.load(selectedBookMarkSetPref);
    Assert.isTrue(fRootFolders.size() > 0, Messages.BookMarkExplorer_ERROR_NO_SET_FOUND);
    if (pref != null)
      fSelectedBookMarkSet = new FolderReference(pref.getLong().longValue()).resolve();
    else {
      fSelectedBookMarkSet = getRootFolderAt(0);

      /* Save this to make sure subsequent calls succeed */
      pref = Owl.getModelFactory().createPreference(selectedBookMarkSetPref);
      pref.putLongs(fSelectedBookMarkSet.getId());
      fPrefDAO.save(pref);
    }

    /* Expanded Elements */
    loadExpandedElements();

    /* Selected Folder Child */
    fLastSelectedFolderChild = fGlobalPreferences.getLong(PREF_SELECTED_FOLDER_CHILD);
  }

  /* Expanded Elements - Use ID of selected Set to make it Unique */
  private void loadExpandedElements() {
    IPreference pref = fPrefDAO.load(PREF_EXPANDED_NODES + fSelectedBookMarkSet.getId());
    if (pref != null) {
      for (long element : pref.getLongs())
        fExpandedNodes.add(element);
    }
  }

  void restoreExpandedElements() {
    for (Long expandedNodeId : fExpandedNodes) {
      if (fBookMarkGrouping.getType() == BookMarkGrouping.Type.NO_GROUPING)
        fViewer.setExpandedState(new FolderReference(expandedNodeId), true);
      else
        fViewer.setExpandedState(new EntityGroup(expandedNodeId, BookMarkGrouping.GROUP_CATEGORY_ID), true);
    }
  }

  private IFolder getParent(IStructuredSelection selection) {
    if (!selection.isEmpty()) {
      Object obj = selection.getFirstElement();
      if (obj instanceof IFolder)
        return (IFolder) obj;
      else if (obj instanceof IMark)
        return ((IMark) obj).getParent();
    }

    /* Default is selected Set */
    return fSelectedBookMarkSet;
  }

  private IFolder getRootFolderAt(int index) {
    int i = 0;
    for (IFolder rootFolder : fRootFolders) {
      if (i == index)
        return rootFolder;
      i++;
    }

    return null;
  }

  private int getIndexOfRootFolder(IFolder folder) {
    int i = 0;
    for (IFolder rootFolder : fRootFolders) {
      if (rootFolder.equals(folder))
        return i;
      i++;
    }

    return -1;
  }

  boolean isGroupingEnabled() {
    return fBookMarkGrouping.isActive();
  }

  /**
   * @return <code>true</code> if elements are sorted by name,
   * <code>false</code> otherwise.
   */
  public boolean isSortByNameEnabled() {
    return fBookMarkComparator.getType() == BookMarkSorter.Type.SORT_BY_NAME;
  }

  /**
   * Allows to disable saving settings on dispose. Useful if settings have been
   * imported and the application is to restart.
   *
   * @param saveStateOnDispose <code>true</code> to save settings on dispose and
   * <code>false</code> to block this.
   */
  public void saveStateOnDispose(boolean saveStateOnDispose) {
    fBlockSaveState = !saveStateOnDispose;
  }
}
TOP

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

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.