/* ********************************************************************** **
** 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.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.FileTransfer;
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.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
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.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.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.OpenAction;
import org.rssowl.ui.internal.actions.OpenInBrowserAction;
import org.rssowl.ui.internal.actions.OpenInNewTabAction;
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);
/* Enable "Link to FeedView" */
fViewer.addPostSelectionChangedListener(new ISelectionChangedListener() {
public void selectionChanged(SelectionChangedEvent event) {
onSelectionChanged(event);
}
});
/* Hook Open Support */
fViewer.addOpenListener(new IOpenListener() {
public void open(OpenEvent event) {
OwlUI.openInFeedView(fViewSite.getPage(), (IStructuredSelection) fViewer.getSelection());
}
});
/* 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[] dragTransfers = new Transfer[] { LocalSelectionTransfer.getTransfer(), TextTransfer.getInstance(), URLTransfer.getInstance() };
Transfer[] dropTransfers = new Transfer[] { LocalSelectionTransfer.getTransfer(), TextTransfer.getInstance(), URLTransfer.getInstance(), FileTransfer.getInstance() };
BookMarkDNDImpl bookmarkDND = new BookMarkDNDImpl(this, fViewer);
/* Drag Support */
fViewer.addDragSupport(ops, dragTransfers, bookmarkDND);
/* Drop Support */
fViewer.addDropSupport(ops, dropTransfers, bookmarkDND);
}
private void onSelectionChanged(SelectionChangedEvent event) {
fLastSelection = (IStructuredSelection) event.getSelection();
if (fLinkingEnabled)
linkToFeedView(fLastSelection);
}
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));
final IStructuredSelection selection = (IStructuredSelection) fViewer.getSelection();
IFolder selectedFolder = getFolder(selection);
IPreferenceScope globalPreferences = Owl.getPreferenceService().getGlobalScope();
IPreferenceScope eclipsePreferences = Owl.getPreferenceService().getEclipseScope();
/* Open */
manager.add(new Separator(OwlUI.M_OPEN));
if (!selection.isEmpty()) {
if (!eclipsePreferences.getBoolean(DefaultPreferences.ECLIPSE_SINGLE_CLICK_OPEN))
manager.add(new OpenAction(fViewSite.getPage(), fViewer));
/* Tab related Actions */
if (globalPreferences.getBoolean(DefaultPreferences.ALWAYS_REUSE_FEEDVIEW) && OwlUI.isTabbedBrowsingEnabled()) {
/* Open in new Tab */
manager.add(new OpenInNewTabAction(fViewSite.getPage(), fViewer));
/* Open Feeds of Folder in Tabs */
if (selectedFolder != null)
manager.add(new OpenInNewTabAction(fViewSite.getPage(), selectedFolder));
}
}
manager.add(new GroupMarker(IWorkbenchActionConstants.OPEN_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 */
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 IFolder getFolder(IStructuredSelection selection) {
if (selection.size() == 1) {
Object firstElement = selection.getFirstElement();
if (firstElement instanceof IFolder)
return (IFolder) firstElement;
}
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 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>.
* @param performOnFeedView If <code>TRUE</code>, this navigation should also
* invoke a follow up navigation in the opened feed view if a valid target is
* found and <code>false</code> otherwise.
* @return Returns <code>TRUE</code> in case navigation found a valid item, or
* <code>FALSE</code> otherwise.
*/
public boolean navigate(boolean next, boolean unread, boolean performOnFeedView) {
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, performOnFeedView, unread);
return true;
}
return false;
}
private void performNavigation(ITreeNode targetNode, boolean performOnFeedView, 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 (performOnFeedView && unread)
perform = PerformAfterInputSet.SELECT_UNREAD_NEWS;
else if (performOnFeedView)
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;
}
}