org.rssowl.ui.internal.dialogs.PreviewFeedDialog.java Source code

Java tutorial

Introduction

Here is the source code for org.rssowl.ui.internal.dialogs.PreviewFeedDialog.java

Source

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

import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.IDialogSettings;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.KeyAdapter;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.FontData;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Link;
import org.eclipse.swt.widgets.Shell;
import org.rssowl.core.Owl;
import org.rssowl.core.connection.ConnectionException;
import org.rssowl.core.connection.IProtocolHandler;
import org.rssowl.core.interpreter.InterpreterException;
import org.rssowl.core.interpreter.ParserException;
import org.rssowl.core.persist.IBookMark;
import org.rssowl.core.persist.IFeed;
import org.rssowl.core.persist.INews;
import org.rssowl.core.persist.reference.FeedLinkReference;
import org.rssowl.core.util.CoreUtils;
import org.rssowl.core.util.DateUtils;
import org.rssowl.core.util.StringUtils;
import org.rssowl.core.util.URIUtils;
import org.rssowl.ui.internal.Activator;
import org.rssowl.ui.internal.OwlUI;
import org.rssowl.ui.internal.actions.OpenInBrowserAction;
import org.rssowl.ui.internal.editors.feed.NewsBrowserLabelProvider;
import org.rssowl.ui.internal.util.CBrowser;
import org.rssowl.ui.internal.util.JobRunner;
import org.rssowl.ui.internal.util.LayoutUtils;
import org.rssowl.ui.internal.util.UIBackgroundJob;

import java.io.InputStream;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.List;

/**
 * The {@link PreviewFeedDialog} can be used to preview a {@link IBookMark}s
 * contents without adding it to the list of subscriptions.
 *
 * @author bpasero
 */
public class PreviewFeedDialog extends Dialog {
    private static final int DIALOG_WIDTH_DLUS = 600;
    private static final int DIALOG_HEIGHT_DLUS = 400;
    private static final String DIALOG_SETTINGS_KEY = "org.rssowl.ui.internal.dialogs.PreviewFeedDialog"; //$NON-NLS-1$

    private static final int MAX_NEWS_SHOWN = 50;

    private IBookMark fBookmark;
    private FeedLinkReference fFeedReference;
    private IFeed fLoadedFeed;
    private CBrowser fBrowser;
    private boolean fFirstTimeOpen;
    private NewsBrowserLabelProvider fLabelProvider;
    private String fNewsFontFamily;
    private String fNormalFontCSS;
    private Link fStatusLabel;

    /**
     * @param parentShell
     * @param bookmark
     */
    public PreviewFeedDialog(Shell parentShell, IBookMark bookmark) {
        this(parentShell, bookmark, null, null);
    }

    /**
     * @param parentShell
     * @param bookmark
     * @param feedReference
     */
    public PreviewFeedDialog(Shell parentShell, IBookMark bookmark, FeedLinkReference feedReference) {
        this(parentShell, bookmark, null, feedReference);
    }

    /**
     * @param parentShell
     * @param bookmark
     * @param feed
     */
    public PreviewFeedDialog(Shell parentShell, IBookMark bookmark, IFeed feed) {
        this(parentShell, bookmark, feed, null);
    }

    PreviewFeedDialog(Shell parentShell, IBookMark bookmark, IFeed feed, FeedLinkReference feedReference) {
        super(parentShell);
        fBookmark = bookmark;
        fLoadedFeed = feed;
        fFeedReference = feedReference;
        fFirstTimeOpen = (Activator.getDefault().getDialogSettings().getSection(DIALOG_SETTINGS_KEY) == null);
        createFonts();
    }

    /* Init the Theme Font (from UI Thread) */
    private void createFonts() {
        int fontHeight = 10;
        Font newsFont = OwlUI.getThemeFont(OwlUI.NEWS_TEXT_FONT_ID, SWT.NORMAL);
        FontData[] fontData = newsFont.getFontData();
        if (fontData.length > 0) {
            fNewsFontFamily = fontData[0].getName();
            fontHeight = fontData[0].getHeight();
        }

        int normal = fontHeight;
        String fontUnit = "pt"; //$NON-NLS-1$
        fNormalFontCSS = "font-size: " + normal + fontUnit + ";"; //$NON-NLS-1$ //$NON-NLS-2$
    }

    /*
     * @see org.eclipse.jface.dialogs.TitleAreaDialog#createDialogArea(org.eclipse.swt.widgets.Composite)
     */
    @Override
    protected Control createDialogArea(Composite parent) {

        /* Composite to hold all components */
        Composite composite = new Composite(parent, SWT.NONE);
        composite.setLayout(LayoutUtils.createGridLayout(1, 0, 0));
        composite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));

        /* Browser to preview News */
        fBrowser = new CBrowser(composite, SWT.NONE);
        fBrowser.getControl().setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
        fBrowser.setScriptDisabled(true);
        fBrowser.getControl().addKeyListener(new KeyAdapter() {
            @Override
            public void keyPressed(KeyEvent e) {
                if (e.character == SWT.ESC)
                    close();
            }
        });

        /* Label Provider to produce HTML per News */
        fLabelProvider = new NewsBrowserLabelProvider(fBrowser);

        /* Load and Display the Feed */
        loadFeed();

        /* Separator */
        new Label(parent, SWT.SEPARATOR | SWT.HORIZONTAL)
                .setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, true, false));

        applyDialogFont(composite);

        return composite;
    }

    private void loadFeed() {

        /* Show Info that Feed is loading */
        if (fLoadedFeed == null || fLoadedFeed.getVisibleNews().isEmpty()) {
            if (StringUtils.isSet(fBookmark.getName()))
                showMessage(NLS.bind(Messages.PreviewFeedDialog_LOAD_FEED_N, fBookmark.getName()), false, true);
            else
                showMessage(Messages.PreviewFeedDialog_LOAD_FEED, false, true);
        }

        /* Load Feed in Background */
        JobRunner.runUIUpdater(new UIBackgroundJob(fBrowser.getControl()) {
            private IFeed feed;
            private Exception error;

            @Override
            protected void runInBackground(IProgressMonitor monitor) {

                /* First Check if a Feed was already provided */
                if (fLoadedFeed != null && !fLoadedFeed.getVisibleNews().isEmpty()) {
                    feed = fLoadedFeed;
                    return;
                }

                /* Otherwise Load Feed */
                try {

                    /* Resolve Feed if existing */
                    if (fFeedReference != null)
                        feed = fFeedReference.resolve();

                    /* Create Temporary Feed */
                    if (feed == null || feed.getVisibleNews().isEmpty()) {
                        feed = Owl.getModelFactory().createFeed(null, fBookmark.getFeedLinkReference().getLink());

                        /* Return if dialog closed */
                        if (monitor.isCanceled() || getShell().isDisposed() || fBrowser.getControl().isDisposed())
                            return;

                        /* Retrieve Stream */
                        IProtocolHandler handler = Owl.getConnectionService().getHandler(feed.getLink());
                        InputStream inS = handler.openStream(feed.getLink(), monitor, null);

                        /* Return if dialog closed */
                        if (monitor.isCanceled() || getShell().isDisposed() || fBrowser.getControl().isDisposed())
                            return;

                        /* Interpret Feed */
                        Owl.getInterpreter().interpret(inS, feed, null);
                    }
                } catch (ConnectionException e) {
                    error = e;
                    Activator.safeLogError(e.getMessage(), e);
                } catch (ParserException e) {
                    error = e;
                    Activator.safeLogError(e.getMessage(), e);
                } catch (InterpreterException e) {
                    error = e;
                    Activator.safeLogError(e.getMessage(), e);
                }
            }

            @Override
            protected void runInUI(IProgressMonitor monitor) {
                if (feed != null && error == null)
                    showFeed(feed);
                else if (error != null) {
                    String errorMessage = CoreUtils.toMessage(error);
                    if (StringUtils.isSet(errorMessage))
                        showMessage(NLS.bind(Messages.PreviewFeedDialog_UNABLE_LOAD_FEED, errorMessage), true,
                                false);
                }
            }
        });
    }

    private void showMessage(String msg, boolean isError, boolean showProgress) {
        if (fBrowser.getControl().isDisposed())
            return;

        StringBuilder html = new StringBuilder();
        html.append("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">\n"); //$NON-NLS-1$
        html.append("<html>\n"); //$NON-NLS-1$
        html.append("<body style=\"overflow: auto; font-family: ").append(fNewsFontFamily) //$NON-NLS-1$
                .append(",Verdanna,sans-serif; ").append(fNormalFontCSS).append("\">"); //$NON-NLS-1$ //$NON-NLS-2$

        if (showProgress)
            html.append("<img src=\"" + OwlUI.getImageUri("/icons/obj16/progress.gif", "progress.gif") + "\" />"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$

        if (isError)
            html.append("<span style=\"color: darkred;\">"); //$NON-NLS-1$
        else if (showProgress)
            html.append("<span style=\"padding-left:3px; vertical-align:top;\">"); //$NON-NLS-1$

        html.append(msg);

        if (isError || showProgress)
            html.append("</span>"); //$NON-NLS-1$

        html.append("</body>\n"); //$NON-NLS-1$
        html.append("</html>\n"); //$NON-NLS-1$

        fBrowser.getControl().setText(html.toString());
    }

    private void showFeed(final IFeed feed) {
        if (feed != null && !fBrowser.getControl().isDisposed()) {
            List<INews> news = feed.getNewsByStates(INews.State.getVisible());
            Collections.sort(news, new Comparator<INews>() {
                public int compare(INews news1, INews news2) {
                    Date date1 = DateUtils.getRecentDate(news1);
                    Date date2 = DateUtils.getRecentDate(news2);

                    return date2.compareTo(date1);
                }
            });

            int newsCount = news.size();
            if (news.size() > MAX_NEWS_SHOWN)
                news = news.subList(0, MAX_NEWS_SHOWN);

            /* Render Elements */
            String html = fLabelProvider.render(news.toArray(),
                    (feed.getBase() != null) ? URIUtils.toHTTP(feed.getBase()) : URIUtils.toHTTP(feed.getLink()),
                    true);

            /* Apply to Browser */
            fBrowser.getControl().setText(html);

            /* Also Update Status */
            if (StringUtils.isSet(fBookmark.getName())) {
                StringBuilder str = new StringBuilder();
                if (feed.getHomepage() != null) {
                    str.append(NLS.bind(Messages.PreviewFeedDialog_FOUND_N_NEWS_HOMEPAGE, newsCount,
                            fBookmark.getName()));
                    fStatusLabel.addSelectionListener(new SelectionAdapter() {
                        @Override
                        public void widgetSelected(SelectionEvent e) {
                            new OpenInBrowserAction(new StructuredSelection(feed.getHomepage())).run();
                        }
                    });
                } else
                    str.append(NLS.bind(Messages.PreviewFeedDialog_FOUND_N_NEWS, newsCount, fBookmark.getName()));

                fStatusLabel.setText(str.toString());
            }
        }
    }

    /*
     * @see org.eclipse.jface.window.Window#configureShell(org.eclipse.swt.widgets.Shell)
     */
    @Override
    protected void configureShell(Shell shell) {
        super.configureShell(shell);

        if (StringUtils.isSet(fBookmark.getName()))
            shell.setText(NLS.bind(Messages.PreviewFeedDialog_PREVIEW_OF, fBookmark.getName()));
        else
            shell.setText(Messages.PreviewFeedDialog_PREVIEW);
    }

    /*
     * @see org.eclipse.jface.window.Window#getShellStyle()
     */
    @Override
    protected int getShellStyle() {
        int style = SWT.TITLE | SWT.BORDER | SWT.RESIZE | SWT.MIN | SWT.MAX | SWT.CLOSE | getDefaultOrientation();

        return style;
    }

    /*
     * @see org.eclipse.jface.dialogs.TrayDialog#createButtonBar(org.eclipse.swt.widgets.Composite)
     */
    @Override
    protected Control createButtonBar(Composite parent) {
        GridLayout layout = new GridLayout(1, false);
        layout.marginWidth = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_MARGIN);
        layout.marginHeight = convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_MARGIN);
        layout.horizontalSpacing = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_SPACING);
        layout.verticalSpacing = convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_SPACING);

        Composite buttonBar = new Composite(parent, SWT.NONE);
        buttonBar.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, true, false));
        buttonBar.setLayout(layout);

        /* Status Label */
        fStatusLabel = new Link(buttonBar, SWT.NONE);
        applyDialogFont(fStatusLabel);
        fStatusLabel.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, true));
        if (StringUtils.isSet(fBookmark.getName()))
            fStatusLabel.setText(fBookmark.getName());

        /* Close */
        Button closeButton = createButton(buttonBar, IDialogConstants.CLOSE_ID, IDialogConstants.CLOSE_LABEL,
                false);
        closeButton.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                close();
            }
        });

        return buttonBar;
    }

    /*
     * @see org.eclipse.jface.dialogs.Dialog#getDialogBoundsSettings()
     */
    @Override
    protected IDialogSettings getDialogBoundsSettings() {
        IDialogSettings settings = Activator.getDefault().getDialogSettings();
        IDialogSettings section = settings.getSection(DIALOG_SETTINGS_KEY);
        if (section != null)
            return section;

        return settings.addNewSection(DIALOG_SETTINGS_KEY);
    }

    /*
     * @see org.eclipse.jface.dialogs.Dialog#getDialogBoundsStrategy()
     */
    @Override
    protected int getDialogBoundsStrategy() {
        return Dialog.DIALOG_PERSISTLOCATION | Dialog.DIALOG_PERSISTSIZE;
    }

    /*
     * @see org.eclipse.jface.dialogs.Dialog#initializeBounds()
     */
    @Override
    protected void initializeBounds() {
        super.initializeBounds();

        Shell shell = getShell();

        /* Minimum Size */
        int minWidth = convertHorizontalDLUsToPixels(DIALOG_WIDTH_DLUS);
        int minHeight = convertHorizontalDLUsToPixels(DIALOG_HEIGHT_DLUS);

        /* Required Size */
        Point requiredSize = shell.computeSize(SWT.DEFAULT, SWT.DEFAULT);

        /* Set Size */
        shell.setSize(Math.max(minWidth, requiredSize.x), Math.max(minHeight, requiredSize.y));

        /* Set Location */
        if (fFirstTimeOpen)
            LayoutUtils.positionShell(shell);
    }
}