/* ********************************************************************** **
** 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.editors.feed;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IAction;
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.resource.JFaceResources;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.swt.SWT;
import org.eclipse.swt.browser.Browser;
import org.eclipse.swt.browser.LocationAdapter;
import org.eclipse.swt.browser.LocationEvent;
import org.eclipse.swt.browser.LocationListener;
import org.eclipse.swt.browser.ProgressEvent;
import org.eclipse.swt.browser.ProgressListener;
import org.eclipse.swt.events.FocusEvent;
import org.eclipse.swt.events.FocusListener;
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.Font;
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.Menu;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.IActionDelegate;
import org.eclipse.ui.actions.ActionFactory;
import org.eclipse.ui.dialogs.PreferencesUtil;
import org.rssowl.core.Owl;
import org.rssowl.core.internal.persist.pref.DefaultPreferences;
import org.rssowl.core.persist.pref.IPreferenceScope;
import org.rssowl.core.util.StringUtils;
import org.rssowl.core.util.URIUtils;
import org.rssowl.ui.internal.Application;
import org.rssowl.ui.internal.ApplicationServer;
import org.rssowl.ui.internal.ContextMenuCreator;
import org.rssowl.ui.internal.Controller;
import org.rssowl.ui.internal.OwlUI;
import org.rssowl.ui.internal.ShareProvider;
import org.rssowl.ui.internal.actions.ImportAction;
import org.rssowl.ui.internal.actions.OpenInBrowserAction;
import org.rssowl.ui.internal.actions.SendLinkAction;
import org.rssowl.ui.internal.dialogs.preferences.SharingPreferencesPage;
import org.rssowl.ui.internal.util.BrowserUtils;
import org.rssowl.ui.internal.util.CBrowser;
import org.rssowl.ui.internal.util.LayoutUtils;
import java.util.List;
/**
* The <code>BrowserBar</code> is providing controls to navigate a Browser. This
* includes common actions like 'Forward' and 'Back'. A Text-Field is provided
* to enter URLs.
*
* @author bpasero
*/
public class BrowserBar {
/* Navigate Back */
private static final String BACK_ACTION = "org.rssowl.ui.internal.editors.feed.BackAction"; //$NON-NLS-1$
/* Navigate Forward */
private static final String FORWARD_ACTION = "org.rssowl.ui.internal.editors.feed.ForwardAction"; //$NON-NLS-1$
/* Share Link */
private static final String SHARE_ACTION = "org.rssowl.ui.internal.editors.feed.ShareLinkAction"; //$NON-NLS-1$
private CBrowser fBrowser;
private Composite fParent;
private ToolBarManager fNavigationToolBarManager;
private Text fLocationInput;
private FeedView fFeedView;
private boolean fUseExternalBrowser;
private boolean fLocationSelectAllOnce = true;
private final Font fItalicFont;
/**
* @param feedView
* @param parent
*/
public BrowserBar(FeedView feedView, Composite parent) {
fFeedView = feedView;
fParent = parent;
fItalicFont = OwlUI.getItalic(JFaceResources.DEFAULT_FONT);
IPreferenceScope globalScope = Owl.getPreferenceService().getGlobalScope();
fUseExternalBrowser = globalScope.getBoolean(DefaultPreferences.USE_DEFAULT_EXTERNAL_BROWSER) || globalScope.getBoolean(DefaultPreferences.USE_CUSTOM_EXTERNAL_BROWSER);
createControl();
}
boolean isVisible() {
return !fUseExternalBrowser;
}
/**
* @param browser
*/
public void init(CBrowser browser) {
fBrowser = browser;
registerListeners();
}
private void registerListeners() {
LocationListener locationListener = new LocationAdapter() {
@Override
public void changed(LocationEvent event) {
fNavigationToolBarManager.find(BACK_ACTION).update(IAction.ENABLED);
fNavigationToolBarManager.find(FORWARD_ACTION).update(IAction.ENABLED);
setBusy(false);
}
@Override
public void changing(LocationEvent event) {
setBusy(true);
}
};
ProgressListener progressListener = new ProgressListener() {
public void changed(ProgressEvent event) {
if (!fLocationInput.isDisposed()) {
String url = ((Browser) event.widget).getUrl();
if (ApplicationServer.getDefault().isNewsServerUrl(url)) {
if (ApplicationServer.getDefault().isNewsServerUrl(fLocationInput.getText()))
fLocationInput.setText(""); //$NON-NLS-1$
} else if (!StringUtils.isSet(fLocationInput.getText()))
fLocationInput.setText(URIUtils.ABOUT_BLANK.equals(url) ? "" : url); //$NON-NLS-1$
}
}
/* Reset progress bar on completion */
public void completed(ProgressEvent event) {
if (!fLocationInput.isDisposed()) {
String url = ((Browser) event.widget).getUrl();
if (ApplicationServer.getDefault().isNewsServerUrl(url))
fLocationInput.setText(""); //$NON-NLS-1$
else if (StringUtils.isSet(url)) {
if (URIUtils.ABOUT_BLANK.equals(url))
fLocationInput.setText(""); //$NON-NLS-1$
else if (!fLocationInput.isFocusControl())
fLocationInput.setText(url);
}
}
}
};
fBrowser.getControl().addLocationListener(locationListener);
fBrowser.getControl().addProgressListener(progressListener);
}
private void createControl() {
Composite container = new Composite(fParent, SWT.NONE);
container.setLayout(LayoutUtils.createGridLayout(2, 3, 0, 0, 2, false));
((GridLayout) container.getLayout()).marginBottom = 2;
container.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, true, false));
((GridData) container.getLayoutData()).exclude = fUseExternalBrowser;
/* Navigation ToolBar */
createNavigationToolBar(container);
/* Location Field */
createLocationInput(container);
}
private void createNavigationToolBar(Composite parent) {
fNavigationToolBarManager = new ToolBarManager(SWT.FLAT);
/* New Browser Tab */
IAction newBrowserTab = new Action(Messages.BrowserBar_NEW_TAB) {
@Override
public void run() {
BrowserUtils.openLinkInternal(URIUtils.ABOUT_BLANK, null);
}
};
newBrowserTab.setImageDescriptor(OwlUI.getImageDescriptor("icons/etool16/new_browser_tab.gif")); //$NON-NLS-1$
fNavigationToolBarManager.add(newBrowserTab);
/* Navigate Backward */
fNavigationToolBarManager.add(new Separator());
IAction navBackward = new Action(Messages.BrowserBar_BACK) {
@Override
public void run() {
fBrowser.back();
}
@Override
public boolean isEnabled() {
return fBrowser != null && fBrowser.getControl().isBackEnabled();
}
};
navBackward.setId(BACK_ACTION);
navBackward.setImageDescriptor(OwlUI.getImageDescriptor("icons/etool16/backward.gif")); //$NON-NLS-1$
navBackward.setDisabledImageDescriptor(OwlUI.getImageDescriptor("icons/dtool16/backward.gif")); //$NON-NLS-1$
fNavigationToolBarManager.add(navBackward);
/* Navigate Forward */
IAction navForward = new Action(Messages.BrowserBar_FORWARD) {
@Override
public void run() {
fBrowser.forward();
}
@Override
public boolean isEnabled() {
return fBrowser != null && fBrowser.getControl().isForwardEnabled();
}
};
navForward.setId(FORWARD_ACTION);
navForward.setImageDescriptor(OwlUI.getImageDescriptor("icons/etool16/forward.gif")); //$NON-NLS-1$
navForward.setDisabledImageDescriptor(OwlUI.getImageDescriptor("icons/dtool16/forward.gif")); //$NON-NLS-1$
fNavigationToolBarManager.add(navForward);
/* Stop */
IAction stopNav = new Action(Messages.BrowserBar_STOP) {
@Override
public void run() {
fBrowser.getControl().stop();
setBusy(false);
}
};
stopNav.setImageDescriptor(OwlUI.getImageDescriptor("icons/etool16/cancel.gif")); //$NON-NLS-1$
fNavigationToolBarManager.add(stopNav);
/* Reload */
IAction reload = new Action(Messages.BrowserBar_RELOAD) {
@Override
public void run() {
fBrowser.refresh();
setBusy(true);
}
};
reload.setImageDescriptor(OwlUI.getImageDescriptor("icons/elcl16/reload.gif")); //$NON-NLS-1$
fNavigationToolBarManager.add(reload);
/* Home */
IAction navHome = new Action(Messages.BrowserBar_HOME) {
@Override
public void run() {
fFeedView.getNewsBrowserControl().getViewer().home();
}
};
navHome.setImageDescriptor(OwlUI.getImageDescriptor("icons/etool16/home.gif")); //$NON-NLS-1$
fNavigationToolBarManager.add(navHome);
/* Share */
fNavigationToolBarManager.add(new Separator());
IAction shareLink = new Action(Messages.BrowserBar_SHARE_LINK, IAction.AS_DROP_DOWN_MENU) {
@Override
public void run() {
OwlUI.positionDropDownMenu(this, fNavigationToolBarManager);
}
@Override
public String getId() {
return SHARE_ACTION;
}
};
fNavigationToolBarManager.add(shareLink);
shareLink.setImageDescriptor(OwlUI.SHARE);
shareLink.setMenuCreator(new ContextMenuCreator() {
@Override
public Menu createMenu(Control parent) {
MenuManager shareMenu = new MenuManager();
final IStructuredSelection selection = getSelectionFromBrowser();
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 {
Object obj = selection.getFirstElement();
if (StringUtils.isSet((String) obj) && !URIUtils.ABOUT_BLANK.equals(obj)) {
String shareLink = provider.toShareUrl((String) obj, null);
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.BrowserBar_CONFIGURE) {
@Override
public void run() {
PreferencesUtil.createPreferenceDialogOn(fBrowser.getControl().getShell(), SharingPreferencesPage.ID, null, null).open();
};
});
return shareMenu.createContextMenu(parent);
}
});
/* Discover Feeds on Website */
fNavigationToolBarManager.add(new Separator());
IAction discoverFeeds = new Action(Messages.BrowserBar_FIND_FEEDS) {
@Override
public void run() {
String url = fBrowser.getControl().getUrl();
if (StringUtils.isSet(url) && !ApplicationServer.getDefault().isNewsServerUrl(url) && !URIUtils.ABOUT_BLANK.equals(url))
new ImportAction().openWizard(fBrowser.getControl().getShell(), url);
else
new ImportAction().openWizard(fBrowser.getControl().getShell(), true);
}
};
fNavigationToolBarManager.add(discoverFeeds);
discoverFeeds.setImageDescriptor(OwlUI.getImageDescriptor("icons/etool16/new_bkmrk.gif")); //$NON-NLS-1$
fNavigationToolBarManager.createControl(parent);
}
private IStructuredSelection getSelectionFromBrowser() {
String url = fBrowser.getControl().getUrl();
if (ApplicationServer.getDefault().isNewsServerUrl(url) || URIUtils.ABOUT_BLANK.equals(url))
return StructuredSelection.EMPTY;
return new StructuredSelection(url);
}
private void createLocationInput(Composite parent) {
if (Application.IS_WINDOWS || Application.IS_LINUX)
fLocationInput = new Text(parent, SWT.BORDER | SWT.SINGLE | SWT.SEARCH);
else
fLocationInput = new Text(parent, SWT.BORDER | SWT.SINGLE);
OwlUI.makeAccessible(fLocationInput, Messages.BrowserBar_ENTER_WEBSITE_PHRASE);
fLocationInput.setMessage(Messages.BrowserBar_ENTER_WEBSITE_PHRASE);
fLocationInput.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, true));
fLocationInput.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetDefaultSelected(SelectionEvent e) {
if (StringUtils.isSet(fLocationInput.getText())) {
fBrowser.setUrl(URIUtils.getLink(fLocationInput.getText()));
fBrowser.getControl().setFocus();
}
}
});
/* Select All on Mouse Up */
fLocationInput.addMouseListener(new MouseAdapter() {
@Override
public void mouseUp(MouseEvent e) {
if (fLocationSelectAllOnce && fLocationInput.getSelectionCount() == 0)
fLocationInput.selectAll();
fLocationSelectAllOnce = false;
}
});
/* Register this Input Field to Context Service */
Controller.getDefault().getContextService().registerInputField(fLocationInput);
fLocationInput.addFocusListener(new FocusListener() {
public void focusGained(FocusEvent e) {
fFeedView.getEditorSite().getActionBars().getGlobalActionHandler(ActionFactory.CUT.getId()).setEnabled(true);
fFeedView.getEditorSite().getActionBars().getGlobalActionHandler(ActionFactory.COPY.getId()).setEnabled(true);
fFeedView.getEditorSite().getActionBars().getGlobalActionHandler(ActionFactory.PASTE.getId()).setEnabled(true);
}
public void focusLost(FocusEvent e) {
fFeedView.getEditorSite().getActionBars().getGlobalActionHandler(ActionFactory.CUT.getId()).setEnabled(false);
fFeedView.getEditorSite().getActionBars().getGlobalActionHandler(ActionFactory.COPY.getId()).setEnabled(false);
fFeedView.getEditorSite().getActionBars().getGlobalActionHandler(ActionFactory.PASTE.getId()).setEnabled(false);
fLocationSelectAllOnce = true;
}
});
}
private void setBusy(boolean busy) {
if (fLocationInput.isDisposed())
return;
String url = fLocationInput.getText();
if (busy && StringUtils.isSet(url) && !ApplicationServer.getDefault().isNewsServerUrl(url) && !URIUtils.ABOUT_BLANK.equals(url))
fLocationInput.setFont(fItalicFont);
else
fLocationInput.setFont(null);
}
}