/* ********************************************************************** ** ** Copyright notice ** ** ** ** (c) 2003-2005 RSSOwl Development Team ** ** http://www.rssowl.org/ ** ** ** ** All rights reserved ** ** ** ** This program and the accompanying materials are made available under ** ** the terms of the Common Public License v1.0 which accompanies this ** ** distribution, and is available at: ** ** http://www.rssowl.org/legal/cpl-v10.html ** ** ** ** A copy is found in the file cpl-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 - initial API and implementation (bpasero@rssowl.org) ** ** ** ** ********************************************************************** */package net.sourceforge.rssowl.controller;import net.sourceforge.rssowl.controller.dialog.PreferencesDialog;import net.sourceforge.rssowl.controller.panel.BrowserPanel;import net.sourceforge.rssowl.controller.thread.AmphetaRateThread;import net.sourceforge.rssowl.model.Enclosure;import net.sourceforge.rssowl.model.NewsItem;import net.sourceforge.rssowl.util.GlobalSettings;import net.sourceforge.rssowl.util.i18n.ITranslatable;import net.sourceforge.rssowl.util.shop.BrowserShop;import net.sourceforge.rssowl.util.shop.FontShop;import net.sourceforge.rssowl.util.shop.LayoutDataShop;import net.sourceforge.rssowl.util.shop.LayoutShop;import net.sourceforge.rssowl.util.shop.PaintShop;import net.sourceforge.rssowl.util.shop.RegExShop;import net.sourceforge.rssowl.util.shop.StringShop;import net.sourceforge.rssowl.util.shop.URLShop;import net.sourceforge.rssowl.util.shop.WidgetShop;import net.sourceforge.rssowl.util.shop.XMLShop;import org.eclipse.swt.SWT;import org.eclipse.swt.SWTError;import org.eclipse.swt.custom.SashForm;import org.eclipse.swt.custom.StyledText;import org.eclipse.swt.dnd.DND;import org.eclipse.swt.dnd.DragSource;import org.eclipse.swt.dnd.DragSourceAdapter;import org.eclipse.swt.dnd.DragSourceEvent;import org.eclipse.swt.dnd.TextTransfer;import org.eclipse.swt.dnd.Transfer;import org.eclipse.swt.events.DisposeEvent;import org.eclipse.swt.events.DisposeListener;import org.eclipse.swt.events.MenuAdapter;import org.eclipse.swt.events.MenuEvent;import org.eclipse.swt.events.MouseAdapter;import org.eclipse.swt.events.MouseEvent;import org.eclipse.swt.events.MouseMoveListener;import org.eclipse.swt.events.SelectionAdapter;import org.eclipse.swt.events.SelectionEvent;import org.eclipse.swt.graphics.Point;import org.eclipse.swt.graphics.Rectangle;import org.eclipse.swt.layout.FillLayout;import org.eclipse.swt.layout.FormLayout;import org.eclipse.swt.layout.GridData;import org.eclipse.swt.layout.GridLayout;import org.eclipse.swt.widgets.Composite;import org.eclipse.swt.widgets.Display;import org.eclipse.swt.widgets.Event;import org.eclipse.swt.widgets.Listener;import org.eclipse.swt.widgets.Menu;import org.eclipse.swt.widgets.MenuItem;import org.eclipse.swt.widgets.Shell;import org.eclipse.swt.widgets.ToolBar;import org.eclipse.swt.widgets.ToolItem;import org.eclipse.ui.forms.events.HyperlinkAdapter;import org.eclipse.ui.forms.events.HyperlinkEvent;import org.eclipse.ui.forms.widgets.Hyperlink;import org.jdom.Text;import org.eclipse.swt.events.MouseListener;import org.eclipse.swt.program.Program;import org.eclipse.swt.widgets.Button;import org.eclipse.swt.widgets.Control;import java.util.Iterator;import java.util.Vector;import java.util.Hashtable;import java.util.Enumeration;import java.util.Map;/** * This is the ViewForm where a newsitem is displayed with Title, URL to the * news and the description. * * @author <a href="mailto:bpasero@rssowl.org">Benjamin Pasero </a> * @version 1.2 */public class NewsText implements ITranslatable, IFontChangeable { private BrowserPanel browserPanel; private SashForm contentSash; private MenuItem copyItemUrl; private Composite descriptionHolder; private boolean isShowingNews; private Menu linkMenu; private Composite newsContentHolder; private ViewForm newsContentViewForm; private Composite newsContentViewFormHeader; private Composite newsTextHolder; private MenuItem openExternalItem; private MenuItem printNews; private MenuItem rateBad; private MenuItem rateFantastic; private MenuItem rateGood; private MenuItem rateModerate; private MenuItem rateVeryBad; private boolean requiresUpdate; private MenuItem selectAllItem; private MenuItem useBrowserForNewsText; MenuItem copyItem; Display display; EventManager eventManager; boolean isReset; int lastRate; StyledText newsText; Menu newsTextMenu; StyledText newsTextTitle; StyledText rcTitle; ToolBar newsTextToolBar; Hyperlink newsTextUrl; StyledText rcLocalFiles; Button playPodcast; GridLayout rcLayout; GridData rcData; MenuItem openInBrowserItem; Composite rateComposite; Menu rateDropdown; ToolItem rateToolItem; NewsItem rssNewsItem; GUI rssOwlGui; Shell shell; Composite urlTitleHolder; Composite rcHolder; int x; int y; /** * Instantiate a new NewsText to display a newsitem * * @param display The display * @param shell The shell * @param contentSash The Sashform where to add the ViewForm * @param rssOwlGui Access some methods of the main controller * @param eventManager The event manager */ public NewsText(Display display, Shell shell, SashForm contentSash, GUI rssOwlGui, EventManager eventManager) { this.display = display; this.shell = shell; this.contentSash = contentSash; this.rssOwlGui = rssOwlGui; this.eventManager = eventManager; isReset = true; isShowingNews = false; requiresUpdate = true; lastRate = AmphetaRateThread.RATE_MODERATE; initComponents(); } /** * Get the BrowserPanel of the Newstext panel in case internal browser view is * activated for newstext * * @return BrowserPanel The browserpanel for the newstext */ public BrowserPanel getBrowserPanel() { return browserPanel; } /** * Let other objects access this controll (for example to focus on it) * * @return NewsTextTitle StyledText */ public StyledText getNewsTextTitle() { return newsTextTitle; } /** * Get the currently viewed newsitem's text to print. * * @return String Text to print */ public String getPrintableNewstext() { String printableText = ""; /** Create printable description */ if (rssNewsItem != null) printableText = rssNewsItem.toPrintable(); return printableText; } /** * Explicitly marks the newstext as required to update. This is called when * the user has clicked into a news. */ public void setRequiresUpdate() { requiresUpdate = true; } /** * @see net.sourceforge.rssowl.controller.IFontChangeable#updateFonts() */ public void updateFonts() { /** Update StyledText font */ if (WidgetShop.isset(newsText)) { newsText.setFont(FontShop.textFont); } /** Update Browser Font */ else if (browserPanel != null && rssNewsItem != null && WidgetShop.isset(browserPanel.getBrowser())) { rssNewsItem.setRequiresViewUpdate(true); displayNews(rssNewsItem); } newsTextTitle.setFont(FontShop.textBoldFont); newsTextUrl.setFont(FontShop.textFont); } /** Update all controlls text with i18n */ public void updateI18N() { rateFantastic.setText(GUI.i18n.getTranslation("RATE_FANTASTIC")); rateGood.setText(GUI.i18n.getTranslation("RATE_GOOD")); rateModerate.setText(GUI.i18n.getTranslation("RATE_MODERATE")); rateBad.setText(GUI.i18n.getTranslation("RATE_BAD")); rateVeryBad.setText(GUI.i18n.getTranslation("RATE_VERY_BAD")); rateToolItem.setToolTipText(GUI.i18n.getTranslation("TOOLTIP_RATE")); copyItemUrl.setText(GUI.i18n.getTranslation("POP_COPY")); if (openExternalItem != null) openExternalItem.setText(GUI.i18n.getTranslation("POP_OPEN_EXTERN")); /** Init the Mnemonics */ MenuManager.initMnemonics(linkMenu); /** Update non-browser controlls */ if (!GlobalSettings.useBrowserForNewsText) { /** Only update if newstext was created before and was not disposed */ if (WidgetShop.isset(newsText)) { updateAccelerators(); openInBrowserItem.setText(GUI.i18n.getTranslation("POP_OPEN_IN_BROWSER")); /** Init the Mnemonics */ MenuManager.initMnemonics(newsTextMenu); } } } /** Update color of Link Label */ public void updateLinkColor() { newsTextUrl.setForeground(PaintShop.linkColor); } /** * Create the browser panel to display newstext in the internal browser * * @param onStartup If TRUE this method is called on startup of RSSOwl */ private void createBrowserPanel(boolean onStartup) { try { browserPanel = new BrowserPanel(rssOwlGui, descriptionHolder, false); browserPanel.getBrowserPanel().setLayoutData(LayoutDataShop.createFormData(0, 0, 0, 0)); } /** If OS fails to build internal browser, dont use it! */ catch (SWTError e) { GUI.logger.log("displayNewsInBrowser()", e); /** Set browser to null explicitly */ if (browserPanel != null) { browserPanel.dispose(); browserPanel = null; } /** Display the news in the styled text */ GlobalSettings.useBrowserForNewsText = false; /** Reset MenuItem and ToolItem */ rssOwlGui.getRSSOwlMenu().setUseBrowserForNewsText(GlobalSettings.useBrowserForNewsText); /** Show info to the user if not called from startup */ if (!onStartup) MessageBoxFactory.showError(shell, BrowserShop.createBrowserError(e)); /** Create styled text and display news */ createStyledText(); /** Recreate the Newstext using StyledText */ rebuildNewsText(); } } /** * Create the StyledText to display the newstext. This method is called * whenever the user switches from the internal browser view to the StyledText * view. */ private void createStyledText() { /** StyledText to display the news description */ newsText = new StyledText(descriptionHolder, SWT.READ_ONLY | SWT.WRAP | SWT.V_SCROLL); newsText.setLayoutData(LayoutDataShop.createFormData(8, 0, 8, -1)); newsText.setFont(FontShop.textFont); newsText.setBackground(display.getSystemColor(SWT.COLOR_WHITE)); newsText.setCursor(display.getSystemCursor(SWT.CURSOR_IBEAM)); newsText.setCaret(null); /** Remove selection from Title and URL if selected */ newsText.addSelectionListener(new SelectionAdapter() { public void widgetSelected(SelectionEvent e) { if (newsTextTitle != null) newsTextTitle.setSelection(0); } }); /** Listen for the mouseposition and check if the mouse is over an URL * */ newsText.addMouseMoveListener(new MouseMoveListener() { public void mouseMove(MouseEvent e) { onMouseMove(e); } }); /** Handle Mouse Up Evnt */ newsText.addMouseListener(new MouseAdapter() { public void mouseUp(MouseEvent e) { onMouseUp(e); } }); /** A popupmenu for the StyledText */ newsTextMenu = new Menu(newsText); /** Display newstext in internal browser if possible */ if (GlobalSettings.useInternalBrowser()) { useBrowserForNewsText = new MenuItem(newsTextMenu, SWT.NONE); if (!GlobalSettings.isMac()) { useBrowserForNewsText.setImage(PaintShop.loadImage("/img/icons/browserview.gif")); useBrowserForNewsText.addDisposeListener(DisposeListenerImpl.getInstance()); } useBrowserForNewsText.addSelectionListener(new SelectionAdapter() { public void widgetSelected(SelectionEvent e) { eventManager.actionSetBrowserView(true); } }); /** Separator */ new MenuItem(newsTextMenu, SWT.SEPARATOR); } /** Copy selection */ copyItem = new MenuItem(newsTextMenu, SWT.NONE); if (!GlobalSettings.isMac()) copyItem.setImage(PaintShop.iconCopy); copyItem.addSelectionListener(new SelectionAdapter() { /** Copy selection to clipboard */ public void widgetSelected(SelectionEvent e) { if (!newsText.getSelectionText().equals("")) { newsText.copy(); } } }); /** Select all text of the StyledText */ selectAllItem = new MenuItem(newsTextMenu, SWT.NONE); selectAllItem.addSelectionListener(new SelectionAdapter() { /** Selection the whole text */ public void widgetSelected(SelectionEvent e) { newsText.selectAll(); } }); /** Separator */ new MenuItem(newsTextMenu, SWT.SEPARATOR); /** Printing is only supported on Windows and Mac */ if (GlobalSettings.usePrinting()) { /** Print news */ printNews = new MenuItem(newsTextMenu, SWT.NONE); if (!GlobalSettings.isMac()) printNews.setImage(PaintShop.iconPrint); printNews.addSelectionListener(new SelectionAdapter() { /** Print news */ public void widgetSelected(SelectionEvent e) { eventManager.actionPrintNews(); } }); /** Separator */ new MenuItem(newsTextMenu, SWT.SEPARATOR); } /** Open the selected text in the browser */ openInBrowserItem = new MenuItem(newsTextMenu, SWT.NONE); openInBrowserItem.setText(GUI.i18n.getTranslation("POP_OPEN_IN_BROWSER")); openInBrowserItem.addSelectionListener(new SelectionAdapter() { /** Open the selection in browser */ public void widgetSelected(SelectionEvent e) { eventManager.actionOpenURL(newsText.getSelectionText()); } }); /** Dynamically Enable / Disable MenuItems */ newsTextMenu.addMenuListener(new MenuAdapter() { public void menuShown(MenuEvent e) { /** First check Widget */ if (!WidgetShop.isset(newsText)) return; /** User has selected text */ if (newsText.getSelectionText().equals("")) { copyItem.setEnabled(false); openInBrowserItem.setEnabled(false); } /** User has not selected text */ else { copyItem.setEnabled(true); openInBrowserItem.setEnabled(true); } } }); /** Set Accelerators */ updateAccelerators(); /** Set Mnemonics */ MenuManager.initMnemonics(newsTextMenu); /** Apply menu */ newsText.setMenu(newsTextMenu); } /** * Display news in the ViewForm * * @param rssNewsItem The newsitem to display */ private void displayNews(NewsItem rssNewsItem) { /** Return in case the news is already showing and an update is not req. */ if (!requiresUpdate && isShowingNews(rssNewsItem)) return; /** This is a new news to display or no news was displayed */ this.rssNewsItem = rssNewsItem; /** Update flags */ isShowingNews = true; requiresUpdate = false; this.rssNewsItem.setRequiresViewUpdate(false); /** Tell MenuManager that the newstext is filled */ MenuManager.notifyState(MenuManager.NEWS_TEXT_FILLED); /** Get Link */ String link = rssNewsItem.getLink(); if (!StringShop.isset(link) && StringShop.isset(rssNewsItem.getGuid()) && RegExShop.isValidURL(rssNewsItem.getGuid())) link = rssNewsItem.getGuid(); /** If this newsItem has no description and the user chose to directOpen */ if (!StringShop.isset(rssNewsItem.getDescription()) && GlobalSettings.directOpenNews && StringShop.isset(link)) displayNewsLinkInBrowser(link); /** User chose to open each news in Browser */ else if (GlobalSettings.directOpenEachNews && StringShop.isset(link)) displayNewsLinkInBrowser(link); /** Display news in the internal browser */ else if (GlobalSettings.useBrowserForNewsText) displayNewsInBrowser(); /** Display news in a StyledText */ else displayNewsInStyledText(); /** Show Rate Dropdown */ rateComposite.setVisible(true); /** Layout components */ descriptionHolder.layout(); } /** * Display the selected news in the internal browser. This will display Title * and URL of the news as usual and show the description (plus possible * enclosures, comments, source) in the internal browser. */ private void displayNewsInBrowser() { /** Display title and link of the news */ displayNewsMetaInfo(); /** Create the browserPanel if not yet done */ if (browserPanel == null) createBrowserPanel(false); /** Let the browser display the rest of the news */ if (browserPanel != null) browserPanel.displayNews(rssNewsItem); /** Browser creation failed, display news in StyledText */ else displayNews(rssNewsItem); } /** * Display selected news in a StyledText */ private void displayNewsInStyledText() { /** Create the StyledText if not yet done */ if (newsText == null || newsText.isDisposed()) createStyledText(); /** Display title and link of the news */ displayNewsMetaInfo(); /** Update Links in Copy Menu */ int items = newsTextMenu.getItemCount(); int linksBegin = 4 + ((GlobalSettings.useInternalBrowser()) ? 2 : 0) + ((GlobalSettings.usePrinting()) ? 2 : 0); for (int i = linksBegin; i < items; i++) newsTextMenu.getItem(linksBegin).dispose(); /** Description of the news */ if (StringShop.isset(rssNewsItem.getDescription())) { newsText.setText(XMLShop.stripSimpleHTMLTags(Text.normalizeString(rssNewsItem.getDescription()))); /** Add the Links from the description to the popupmenu */ if (rssNewsItem.getLinkList() != null && rssNewsItem.getLinkList().size() > 0) { /** Separator */ new MenuItem(newsTextMenu, SWT.SEPARATOR); Iterator linkListIt = rssNewsItem.getLinkList().iterator(); /** Foreach link in the text */ while (linkListIt.hasNext()) { /** Add a menuitem foreach URL from the text */ final MenuItem linkFromText = new MenuItem(newsTextMenu, SWT.NONE); linkFromText.setText((String) linkListIt.next()); if (!GlobalSettings.isMac()) { linkFromText.setImage(PaintShop.iconWorld); } linkFromText.addSelectionListener(new SelectionAdapter() { /** URL openes after click on it */ public void widgetSelected(SelectionEvent e) { eventManager.actionOpenURL(linkFromText.getText(), linkFromText.getText().equals(rssNewsItem.getOrigurl())); } }); } } } /** Selected news has no description */ else { newsText.setText(GUI.i18n.getTranslation("NEWS_NO_DESCRIPTION")); } /** Vector containing all StyleRanges for the Newstext */ Vector styleRanges = new Vector(); /** Paint clickable links in selected link-color */ if (rssNewsItem.getLinkList() != null) styleRanges.addAll(WidgetShop.calculateStyleRanges(newsText, new Vector(rssNewsItem.getLinkList()), PaintShop.linkColor, display.getSystemColor(SWT.COLOR_WHITE), SWT.NORMAL, false, true)); /** Highlight words if serch was performed */ if (rssNewsItem.getHighlightWords() != null) styleRanges.addAll(WidgetShop.calculateStyleRanges(newsText, rssNewsItem.getHighlightWords(), display.getSystemColor(SWT.COLOR_BLACK), PaintShop.syntaxHighlightColor, 0, rssNewsItem.isSearchCaseSensitive(), false)); /** Enclosures */ if (rssNewsItem.getEnclosures() != null && rssNewsItem.getEnclosures().size() > 0) { String enclosureTitle = "\n\n" + GUI.i18n.getTranslation("NEWS_ITEM_INFO_ENCLOSURE") + ":\n"; newsText.append(enclosureTitle); /** Highlight */ styleRanges.addAll(WidgetShop.calculateStyleRanges(newsText, StringShop.toVector(new String[] { GUI.i18n.getTranslation("NEWS_ITEM_INFO_ENCLOSURE") + ":" }), display.getSystemColor(SWT.COLOR_BLACK), display.getSystemColor(SWT.COLOR_WHITE), SWT.BOLD, true, false)); /** Give out all enclosures */ for (int a = 0; a < rssNewsItem.getEnclosures().size(); a++) { Enclosure enclosure = (Enclosure) rssNewsItem.getEnclosures().get(a); newsText.append("\n" + enclosure.getUrl() + " (" + enclosure.getType() + " / " + enclosure.getLength(true) + ")"); } } /** Source of the news */ if (rssNewsItem.getSource() != null) { String source = "\n\n" + GUI.i18n.getTranslation("NEWS_ITEM_INFO_SOURCE") + ": " + rssNewsItem.getSource(); newsText.append(source); /** Highlight */ styleRanges.addAll(WidgetShop.calculateStyleRanges(newsText, StringShop.toVector(new String[] { GUI.i18n.getTranslation("NEWS_ITEM_INFO_SOURCE") + ":" }), display.getSystemColor(SWT.COLOR_BLACK), display.getSystemColor(SWT.COLOR_WHITE), SWT.BOLD, true, false)); } /** Comments to this news */ if (rssNewsItem.getComments() != null && rssNewsItem.getComments().size() > 0) { newsText.append("\n\n" + GUI.i18n.getTranslation("NEWS_ITEM_INFO_COMMENTS") + ":\n"); /** Highlight */ styleRanges.addAll(WidgetShop.calculateStyleRanges(newsText, StringShop.toVector(new String[] { GUI.i18n.getTranslation("NEWS_ITEM_INFO_COMMENTS") + ":" }), display.getSystemColor(SWT.COLOR_BLACK), display.getSystemColor(SWT.COLOR_WHITE), SWT.BOLD, true, false)); /** Give out all comments */ for (int a = 0; a < rssNewsItem.getComments().size(); a++) if (rssNewsItem.getComments().get(a) != null && !rssNewsItem.getComments().get(a).equals("")) newsText.append("\n" + rssNewsItem.getComments().get(a)); } /** Add StyleRanges */ WidgetShop.highlightText(newsText, styleRanges); } /** * Display the Link of the News using the internal browser. * * @param link The valid link of the Newsitem to display. */ private void displayNewsLinkInBrowser(String link) { /** Show the link inside the newstext panel */ if (GlobalSettings.useBrowserForNewsText) { /** Display title and link of the news */ displayNewsMetaInfo(); /** Create the browserPanel if not yet done */ if (browserPanel == null) createBrowserPanel(false); /** Let the browser display the rest of the news */ if (browserPanel != null) { /** Reset to empty page */ browserPanel.getBrowser().setUrl(URLShop.ABOUT_BLANK); /** Set visibility */ if (!browserPanel.getBrowserPanel().isVisible()) browserPanel.getBrowserPanel().setVisible(true); /** Load Link */ browserPanel.getBrowser().setUrl(link); } /** Browser creation failed, display news in StyledText */ else displayNews(rssNewsItem); } /** Show the link inside a new Tab or external */ else { eventManager.actionOpenURL(link); } } /** * Display Title and link of the news */ private void displayNewsMetaInfo() { /** Title of the news */ if (rssNewsItem.getTitle() != null) { newsTextTitle.setText(rssNewsItem.getTitle()); /** Highlight words if serch was performed */ if (rssNewsItem.getHighlightWords() != null) WidgetShop.highlightText(newsTextTitle, rssNewsItem.getHighlightWords(), display.getSystemColor(SWT.COLOR_BLACK), PaintShop.syntaxHighlightColor, 0, rssNewsItem.isSearchCaseSensitive(), false); } /** Title somehow not given */ else { newsTextTitle.setText(GUI.i18n.getTranslation("NO_TITLE")); } /** Link of the news */ if (rssNewsItem.getLink() != null) newsTextUrl.setText(rssNewsItem.getLink()); /** Try the guid as link */ else if (rssNewsItem.getGuid() != null && RegExShop.isValidURL(rssNewsItem.getGuid())) newsTextUrl.setText(rssNewsItem.getGuid()); /** Clear newsTextUrl in any other case */ else newsTextUrl.setText(""); /** Remove tooltip if URL is not given */ if (newsTextUrl.getText().equals("")) { newsTextUrl.setToolTipText(null); newsTextUrl.setVisible(false); } /** Set tooltip and cursor if URL is given */ else { newsTextUrl.setVisible(true); } /** Set RESTcast local files */ Hashtable<String, Hashtable> rcFiles = rssNewsItem.getRcFilesLocal(); if(!rcFiles.isEmpty()) { Composite parent = rcHolder.getParent(); rcHolder.dispose(); parent.redraw(); createRcLocalFiles(); Iterator i = rcFiles.entrySet().iterator(); while(i.hasNext()) { Map.Entry me = (Map.Entry) i.next(); //String key = (String) me.getKey(); //System.out.println(key); Hashtable<String, String> props = (Hashtable) me.getValue(); if(props.get("downloaded") == "true") { addFile(props.get("name"), props.get("location")); //System.out.println(props.get("name")); //rcLocalFiles.setText(props.get("name")); //System.out.println(rcLocalFiles.getText()); //rcLocalFiles.setVisible(true); //rcLocalFiles.setToolTipText("hello"); //rcTitle.setText("mine"); //rcLocalFiles.getParent().redraw(); } } // unhide RESTcast files rcData.exclude = false; rcHolder.setVisible(true); rcHolder.getParent().redraw(); rcHolder.getParent().update(); System.out.println("set visible"); } else { Composite parent = rcHolder.getParent(); rcHolder.dispose(); parent.redraw(); createRcLocalFiles(); } /* Enumeration keys = rcFiles.keys(); while(keys.hasMoreElements()) { String key = (String) keys.nextElement(); System.out.println("here " + key); rcLocalFiles.setText("--"+ key); System.out.println("here2 " + key); //newsTextUrl.setText(key); } //} */ /** Layout the ViewForm */ newsContentViewForm.layout(false); /** Show AmphetaRate status label */ String rateLabelMsg = ""; if (AmphetaRateThread.ratedNews.size() > 0) { Integer rating = (Integer) AmphetaRateThread.ratedNews.get(rssNewsItem.toAmphetaRateURL()); /** News was rated before, show rating level */ if (rating != null) rateLabelMsg = GUI.i18n.getTranslation("LABEL_NEWS_RATED") + ": " + AmphetaRateThread.getTranslatedRatingLevel(rating.intValue()); } /** Update Statusline Rate Label */ rssOwlGui.getRSSOwlStatusLine().updateRateLabel(rateLabelMsg); } /** Init all the components */ private void initComponents() { /** Composite holding the View of a news */ newsContentHolder = new Composite(contentSash, SWT.NONE); newsContentHolder.setLayout(new FillLayout()); /** ViewForm holding the news text */ newsContentViewForm = new ViewForm(newsContentHolder, SWT.BORDER); newsContentViewForm.setTopCenterSeparate(true, false); /** Composite holding URL, Title and Rate Button */ newsContentViewFormHeader = new Composite(newsContentViewForm, SWT.NONE); newsContentViewFormHeader.setLayout(LayoutShop.createGridLayout(2, 0, 0)); newsContentViewFormHeader.setBackground(PaintShop.grayViewFormColor); /** Holder for Title and URL */ urlTitleHolder = new Composite(newsContentViewFormHeader, SWT.NONE); urlTitleHolder.setBackground(PaintShop.grayViewFormColor); urlTitleHolder.setLayout(LayoutShop.createGridLayout(1, 8, 8)); urlTitleHolder.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, true, false, 1, 2)); /** Display the title of the news text */ newsTextTitle = new StyledText(urlTitleHolder, SWT.READ_ONLY | SWT.WRAP); newsTextTitle.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, true, false)); newsTextTitle.setBackground(PaintShop.grayViewFormColor); newsTextTitle.setFont(FontShop.textBoldFont); newsTextTitle.setCursor(display.getSystemCursor(SWT.CURSOR_IBEAM)); newsTextTitle.setCaret(null); /** Remove selection from URL and description if selected */ newsTextTitle.addSelectionListener(new SelectionAdapter() { public void widgetSelected(SelectionEvent e) { if (WidgetShop.isset(newsText)) newsText.setSelection(0); } }); /* playPodcast = new Button(urlTitleHolder, SWT.FLAT); playPodcast.setLayoutData(new GridData(SWT.NONE, SWT.BEGINNING, true, false)); playPodcast.setText("hello"); //playPodcast.setImage(PaintShop.iconPodcastPlayer); playPodcast.setVisible(true); */ /** * This composite is used to display the Hyperlink widget. It is needed * because of a bug that will overflow the text on the right-end out of the * parent widget. */ Composite urlHolder = new Composite(urlTitleHolder, SWT.WRAP); urlHolder.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, true, false)); urlHolder.setLayout(LayoutShop.createGridLayout(1, 0, 0)); urlHolder.setBackground(PaintShop.grayViewFormColor); /** URL of the news text as Hyperlink Widget */ newsTextUrl = new Hyperlink(urlHolder, SWT.WRAP | SWT.NO_FOCUS); newsTextUrl.setBackground(PaintShop.grayViewFormColor); newsTextUrl.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, true, false)); newsTextUrl.setForeground(PaintShop.linkColor); newsTextUrl.setFont(FontShop.textFont); newsTextUrl.setUnderlined(true); /** We have to init the link with a String */ newsTextUrl.setText(""); /** Allow to Drag the Link */ final DragSource linkDragSource = new DragSource(newsTextUrl, DND.DROP_MOVE | DND.DROP_COPY); linkDragSource.setTransfer(new Transfer[] { TextTransfer.getInstance() }); linkDragSource.addDragListener(new DragSourceAdapter() { /** Set URL Data Slot */ public void dragSetData(DragSourceEvent event) { if (StringShop.isset(newsTextUrl.getText())) event.data = newsTextUrl.getText(); } /** Dragging has begun */ public void dragStart(DragSourceEvent event) { event.doit = StringShop.isset(newsTextUrl.getText()); } }); /** Dispose Drag Support on Link Dispose */ newsTextUrl.addDisposeListener(new DisposeListener() { public void widgetDisposed(DisposeEvent e) { linkDragSource.dispose(); } }); /** Popup menue for the newsTextUrl component */ linkMenu = new Menu(newsTextTitle); copyItemUrl = new MenuItem(linkMenu, SWT.NONE); copyItemUrl.setText(GUI.i18n.getTranslation("POP_COPY")); if (!GlobalSettings.isMac()) copyItemUrl.setImage(PaintShop.iconCopy); copyItemUrl.addSelectionListener(new SelectionAdapter() { /** Copy URL to clipboard */ public void widgetSelected(SelectionEvent e) { eventManager.actionCopyText(newsTextUrl); } }); /** Offer the user the possibility to open the link external */ if (GlobalSettings.useInternalBrowser() && !GlobalSettings.openBrowserExtern) { /** Separator */ new MenuItem(linkMenu, SWT.SEPARATOR); openExternalItem = new MenuItem(linkMenu, SWT.NONE); openExternalItem.setText(GUI.i18n.getTranslation("POP_OPEN_EXTERN")); openExternalItem.addSelectionListener(new SelectionAdapter() { public void widgetSelected(SelectionEvent e) { if (StringShop.isset(newsTextUrl.getText())) eventManager.actionOpenURLExternal(newsTextUrl.getText()); } }); } /** Init the Mnemonics */ MenuManager.initMnemonics(linkMenu); /** Apply menu */ newsTextUrl.setMenu(linkMenu); /** Open URL after click */ newsTextUrl.addHyperlinkListener(new HyperlinkAdapter() { public void linkActivated(HyperlinkEvent e) { boolean openExternal = (e.getStateMask() & SWT.CTRL) != 0 || (e.getStateMask() & SWT.COMMAND) != 0; if (StringShop.isset(newsTextUrl.getText())) { if (openExternal) eventManager.actionOpenURLExternal(newsTextUrl.getText()); else eventManager.actionOpenURL(newsTextUrl.getText()); } } }); createRcLocalFiles(); /** Composite for the rate-dropdown and the info textfield */ rateComposite = new Composite(newsContentViewFormHeader, SWT.NONE); rateComposite.setLayout(LayoutShop.createGridLayout(2, 0, 0)); rateComposite.setBackground(PaintShop.grayViewFormColor); rateComposite.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING | GridData.VERTICAL_ALIGN_BEGINNING)); /** Toolbar that holds the rate-dropdown */ newsTextToolBar = new ToolBar(rateComposite, SWT.FLAT); newsTextToolBar.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING | GridData.VERTICAL_ALIGN_BEGINNING)); newsTextToolBar.setBackground(PaintShop.grayViewFormColor); /** Dropdown to rate a newstext */ rateDropdown = new Menu(newsContentViewForm); /** AmphetaRate Level: Fantastic */ rateFantastic = new MenuItem(rateDropdown, SWT.RADIO); rateFantastic.setText(GUI.i18n.getTranslation("RATE_FANTASTIC")); rateFantastic.addSelectionListener(new SelectionAdapter() { public void widgetSelected(SelectionEvent e) { if (((MenuItem) e.getSource()).getSelection()) { lastRate = AmphetaRateThread.RATE_FANTASTIC; eventManager.actionRateNews(rssNewsItem, lastRate); } } }); /** AmphetaRate Level: Good */ rateGood = new MenuItem(rateDropdown, SWT.RADIO); rateGood.setText(GUI.i18n.getTranslation("RATE_GOOD")); rateGood.addSelectionListener(new SelectionAdapter() { public void widgetSelected(SelectionEvent e) { if (((MenuItem) e.getSource()).getSelection()) { lastRate = AmphetaRateThread.RATE_GOOD; eventManager.actionRateNews(rssNewsItem, lastRate); } } }); /** AmphetaRate Level: Moderate */ rateModerate = new MenuItem(rateDropdown, SWT.RADIO); rateModerate.setText(GUI.i18n.getTranslation("RATE_MODERATE")); rateModerate.setSelection(true); rateModerate.addSelectionListener(new SelectionAdapter() { public void widgetSelected(SelectionEvent e) { if (((MenuItem) e.getSource()).getSelection()) { lastRate = AmphetaRateThread.RATE_MODERATE; eventManager.actionRateNews(rssNewsItem, lastRate); } } }); /** AmphetaRate Level: Bad */ rateBad = new MenuItem(rateDropdown, SWT.RADIO); rateBad.setText(GUI.i18n.getTranslation("RATE_BAD")); rateBad.addSelectionListener(new SelectionAdapter() { public void widgetSelected(SelectionEvent e) { if (((MenuItem) e.getSource()).getSelection()) { lastRate = AmphetaRateThread.RATE_BAD; eventManager.actionRateNews(rssNewsItem, lastRate); } } }); /** AmphetaRate Level: Very Bad */ rateVeryBad = new MenuItem(rateDropdown, SWT.RADIO); rateVeryBad.setText(GUI.i18n.getTranslation("RATE_VERY_BAD")); rateVeryBad.addSelectionListener(new SelectionAdapter() { public void widgetSelected(SelectionEvent e) { if (((MenuItem) e.getSource()).getSelection()) { lastRate = AmphetaRateThread.RATE_VERY_BAD; eventManager.actionRateNews(rssNewsItem, lastRate); } } }); /** ToolItem to rate */ rateToolItem = new ToolItem(newsTextToolBar, SWT.DROP_DOWN); rateToolItem.setImage(PaintShop.loadImage("/img/icons/rate.gif")); rateToolItem.setToolTipText(GUI.i18n.getTranslation("TOOLTIP_RATE")); rateToolItem.addDisposeListener(DisposeListenerImpl.getInstance()); /** This listener will place the popup menue to the right place */ rateToolItem.addListener(SWT.Selection, new Listener() { public void handleEvent(Event event) { /** Make popupmenue visible */ if (event.detail == SWT.ARROW) { Rectangle rect = rateToolItem.getBounds(); Point pt = new Point(rect.x, rect.y + rect.height); pt = newsTextToolBar.toDisplay(pt); rateDropdown.setLocation(pt.x, pt.y); rateDropdown.setVisible(true); } /** Perform a rating on the news */ else { rateNews(rssNewsItem, lastRate); } } }); /** Register to MenuManager */ MenuManager.registerRate(rateToolItem); /** Apply Header to ViewForm */ newsContentViewForm.setTopCenter(newsContentViewFormHeader, false); /** TextArea that displays the news text */ newsTextHolder = new Composite(newsContentViewForm, SWT.NONE); newsTextHolder.setBackground(display.getSystemColor(SWT.COLOR_WHITE)); newsTextHolder.setLayout(LayoutShop.createGridLayout(1, 0, 0)); /** Holder for the main text of the news */ descriptionHolder = new Composite(newsTextHolder, SWT.NONE); descriptionHolder.setBackground(display.getSystemColor(SWT.COLOR_WHITE)); descriptionHolder.setLayoutData(LayoutDataShop.createGridData(GridData.FILL_BOTH, 1)); descriptionHolder.setLayout(new FormLayout()); /** Apply control to viewform */ newsContentViewForm.setContent(newsTextHolder, true); /** Newstext is empty at begin */ MenuManager.notifyState(MenuManager.NEWS_TEXT_EMPTY); /** Create the browserPanel to display news if set so */ if (GlobalSettings.useBrowserForNewsText) createBrowserPanel(true); /** Create the styledtext to display news if set so */ else createStyledText(); }private void addFile(String name, String location) { final String loc = location; rcLocalFiles = new StyledText(rcHolder, SWT.READ_ONLY | SWT.WRAP); //rcLocalFiles = new Hyperlink(rcHolder, SWT.WRAP | SWT.NO_FOCUS); rcLocalFiles.setBackground(PaintShop.grayViewFormColor); rcLocalFiles.setLayoutData(new GridData(SWT.BEGINNING, SWT.BEGINNING, false, false)); rcLocalFiles.setForeground(PaintShop.linkColor); rcLocalFiles.setFont(FontShop.textFont); //rcLocalFiles.setUnderlined(true); rcLocalFiles.setText(name); rcLocalFiles.addMouseListener(new MouseListener() { public void mouseDoubleClick(MouseEvent arg0) { Program.launch(loc); } public void mouseDown(MouseEvent arg0) { } public void mouseUp(MouseEvent arg0) { } }); rcLocalFiles.getParent().redraw();}private void createRcLocalFiles() { rcHolder = new Composite(urlTitleHolder, SWT.WRAP); rcLayout = LayoutShop.createGridLayout(2, 0, 0); rcData = new GridData(SWT.FILL, SWT.BEGINNING, true, false); rcData.exclude = true; rcHolder.setLayoutData(rcData); rcHolder.setLayout(rcLayout); rcHolder.setBackground(PaintShop.tbuColor); rcHolder.setVisible(false); //rcHolder.setEnabled(true); rcTitle = new StyledText(rcHolder, SWT.READ_ONLY | SWT.WRAP); rcTitle.setLayoutData(new GridData(SWT.BEGINNING, SWT.BEGINNING, false, false)); rcTitle.setBackground(PaintShop.grayViewFormColor); rcTitle.setFont(FontShop.textBoldFont); rcTitle.setCursor(display.getSystemCursor(SWT.CURSOR_IBEAM)); rcTitle.setCaret(null); rcTitle.setText("Downloaded Files: "); rcTitle.addMouseListener(new MouseListener() { public void mouseDoubleClick(MouseEvent arg0) { //FIXME Program.launch("/tmp/uytun"); } public void mouseDown(MouseEvent arg0) { } public void mouseUp(MouseEvent arg0) { } }); rcTitle.setVisible(true); rcTitle.redraw();} /** * Check if the given NewsItem is currently being displayed * * @param newsItem The newsitem to check if being displayed * @return boolean TRUE in case the newsitem is currently displayed */ private boolean isShowingNews(NewsItem newsItem) { return isShowingNews && rssNewsItem != null && rssNewsItem.sameAs(newsItem) && !rssNewsItem.getRequiresViewUpdate(); } /** * Rebuild the newstext area */ private void rebuildNewsText() { newsContentHolder.dispose(); initComponents(); contentSash.layout(); } /** Update the accelerators on the menuitems */ private void updateAccelerators() { if (GlobalSettings.usePrinting()) rssOwlGui.getRSSOwlMenu().updateAccelerator(printNews, "TOOLTIP_PRINT", true, false); if (GlobalSettings.useInternalBrowser()) rssOwlGui.getRSSOwlMenu().updateAccelerator(useBrowserForNewsText, "MENU_BROWSER_FOR_NEWSTEXT", false, false); rssOwlGui.getRSSOwlMenu().updateAccelerator(selectAllItem, "MENU_EDIT_SELECT_ALL", false, false); rssOwlGui.getRSSOwlMenu().updateAccelerator(copyItem, "MENU_EDIT_COPY", false, false); } /** * Get the word from the position where the mouse is and check if the word is * an URL. If an URL was found the setData() method of the StyledText is * called and the URL is inserted as String. Otherwise the setData() method is * called with NULL as argument. * * @param text StyledText to check the word */ void checkWord(StyledText text) { int offset = text.getOffsetAtLocation(new Point(x, y)); int start = offset; int end = offset; boolean leftTerminatorFound = false; boolean rightTerminatorFound = false; /** Dont search if char is whitespace */ if (text.getText(start, start).equals(" ")) return; /** Search for the whole word */ while (true) { /** Left URL Terminating Symbol Search */ if (!leftTerminatorFound) { /** Check if left whitespace was found */ if (StringShop.isTerminating(text.getText(start, start))) { leftTerminatorFound = true; start++; } /** End search, because first char is reached */ else if (start == 0) leftTerminatorFound = true; /** Search at the next left position */ else start--; } /** Right URL Terminating Symbol Search */ if (!rightTerminatorFound) { /** Check if right whitespace was found */ if (StringShop.isTerminating(text.getText(end, end))) { rightTerminatorFound = true; end--; } /** End search, because the last char is reached */ else if (end == text.getText().length() - 1) rightTerminatorFound = true; /** Search at the next right position */ else end++; } /** Complete word was found, end this search */ if (leftTerminatorFound && rightTerminatorFound) break; } /** Get the word from the position where the mouse is */ String curWord = text.getText(start, end).trim(); /** Check if the word is a link */ if (!curWord.equals("") && rssNewsItem.getLinkList() != null && rssNewsItem.getLinkList().contains(curWord)) { text.setCursor(display.getSystemCursor(SWT.CURSOR_HAND)); text.setData(curWord); /** This is a link from AmphetaRate recommendation feed */ if (curWord.equals(rssNewsItem.getOrigurl())) text.setToolTipText(GUI.i18n.getTranslation("BUTTON_ADDTO_FAVORITS")); /** this styledtext needs reset */ isReset = false; } /** The word is not a link */ else { if (!isReset) { text.setCursor(display.getSystemCursor(SWT.CURSOR_IBEAM)); text.setData(null); text.setToolTipText(null); /** this styledtext is reseted */ isReset = true; } } } /** Empty the newstext viewform */ void clearNewstext() { /** Set Flag */ isShowingNews = false; /** Clear newstext title */ newsTextTitle.setText(""); newsTextTitle.setStyleRange(null); /** Clear newstext url */ newsTextUrl.setText(""); newsTextUrl.setVisible(false); /* //rcLocalFiles.setText(""); rcData.exclude = true; rcHolder.setVisible(false); rcHolder.getParent().redraw(); */ /** Remove newsitem */ rssNewsItem = null; /** Clear rate info message */ rssOwlGui.getRSSOwlStatusLine().updateRateLabel(""); /** Clear browserPanel */ if (GlobalSettings.useBrowserForNewsText && browserPanel != null) browserPanel.hideNoControlsBrowser(); /** Clear newstext */ else if (!GlobalSettings.useBrowserForNewsText && newsText != null) newsText.dispose(); /** Hide Rate Dropdown */ rateComposite.setVisible(false); } /** * Display the selected news in the newstext-viewform * * @param urlOrTitle The URL / Path or Title of the RSS XML * @param newsTitle Title of the selected news */ void displayNews(String urlOrTitle, String newsTitle) { NewsItem rssNewsItem = rssOwlGui.getRSSOwlNewsTabFolder().getSelectedNewsItem(newsTitle); /** Return if the selected news item is not available */ if (rssNewsItem == null) return; /** Set newsfeed XML Url to this newsitem if it is not yet set */ if (rssNewsItem.getNewsfeedXmlUrl() == null) rssNewsItem.setNewsfeedXmlUrl(urlOrTitle); /** Display the news in the NewsText ViewForm */ displayNews(rssNewsItem); } /** * Called whenever the mouse is moving * * @param e The occuring MouseEvent */ void onMouseMove(MouseEvent e) { /** Save position */ x = e.x; y = e.y; try { checkWord(newsText); } /** Mouse out of text range */ catch (IllegalArgumentException f) { /** Reset cursor, data and tooltip text */ if (!isReset) { newsText.setCursor(display.getSystemCursor(SWT.CURSOR_IBEAM)); newsText.setData(null); newsText.setToolTipText(null); } /** Update flag */ isReset = true; } } /** * Called whenever the mouse button was released * * @param e The occuring MouseEvent */ void onMouseUp(MouseEvent e) { /** Open URL after click if mouse is hovering above an URL */ if (e.button == 1 && newsText.getSelectionCount() == 0 && newsText.getData() != null) eventManager.actionOpenURL((String) newsText.getData(), ((String) newsText.getData()).equals(rssNewsItem.getOrigurl())); /** * The mouse on Mac does not provide a second mouse button. Display the * popup when the first mouse button is clicked while the ctrl key is * pressed */ if (GlobalSettings.isMac()) { if (e.stateMask == (SWT.BUTTON1 | SWT.CTRL) && WidgetShop.isset(newsTextMenu)) newsTextMenu.setVisible(true); } } /** * Rate selected news * * @param rssNewsItem The newsitem to rate * @param rateLevel The rating level */ void rateNews(NewsItem rssNewsItem, int rateLevel) { /** User has set an AmphetaRate account */ if (AmphetaRateThread.isOldUser() || !GlobalSettings.amphetaRateUsername.equals("")) { boolean rateSuccessfull = AmphetaRateThread.rate(rssNewsItem, rateLevel); /** Wake up submit thread to submit rating */ rssOwlGui.getRSSOwlAmphetaRate().wakeUp(); /** Get the translated rating level */ String rate = AmphetaRateThread.getTranslatedRatingLevel(rateLevel); /** Rating was successfull */ if (rateSuccessfull) rssOwlGui.getRSSOwlStatusLine().updateRateLabel(GUI.i18n.getTranslation("LABEL_NEWS_RATED") + ": " + rate); /** Rating was not successfull */ else rssOwlGui.getRSSOwlStatusLine().updateRateLabel(""); } /** User has not yet set an AmphetaRate user ID */ else { MessageBoxFactory.showMessage(shell, SWT.ICON_WARNING, GUI.i18n.getTranslation("MESSAGEBOX_TITLE_ATTENTION"), GUI.i18n.getTranslation("DIALOG_ID_ATTENTION")); /** Prompt for AmphetaRate User ID */ PreferencesDialog.lastOpenedPropertyPage = 8; new PreferencesDialog(shell, GUI.i18n.getTranslation("MENU_PREFERENCES"), rssOwlGui).open(); } } /** * Update the newstext composite to either show Internal Browser or StyledText * for the newstext */ void updateNewsTextComposite() { /** Create the internal browserPanel */ if (GlobalSettings.useBrowserForNewsText) { try { browserPanel = new BrowserPanel(rssOwlGui, descriptionHolder, false); browserPanel.getBrowserPanel().setLayoutData(LayoutDataShop.createFormData(0, 0, 0, 0)); /** Dispose styledtext */ if (newsText != null) newsText.dispose(); } /** If OS fails to build internal browser, dont use it! */ catch (SWTError e) { GUI.logger.log("updateNewsTextComposite()", e); GlobalSettings.useBrowserForNewsText = false; rssOwlGui.getRSSOwlMenu().useBrowserForNewsText.setSelection(GlobalSettings.useBrowserForNewsText); MessageBoxFactory.showError(shell, BrowserShop.createBrowserError(e)); rebuildNewsText(); } } /** Create the StyledText */ else { /** Dispose the browserPanel if its not null */ if (browserPanel != null) browserPanel.dispose(); /** Create styledtext */ createStyledText(); } /** Layout update */ newsTextHolder.update(); newsTextHolder.layout(); /** Set Flag */ isShowingNews = false; /** Display current newsitem */ if (this.rssNewsItem != null) displayNews(this.rssNewsItem); }}