/* ********************************************************************** **
** 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;
import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Platform;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.ActionContributionItem;
import org.eclipse.jface.action.IContributionItem;
import org.eclipse.jface.action.ToolBarManager;
import org.eclipse.jface.bindings.keys.KeyStroke;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.IDialogSettings;
import org.eclipse.jface.fieldassist.ContentProposalAdapter;
import org.eclipse.jface.fieldassist.ControlDecoration;
import org.eclipse.jface.fieldassist.FieldDecorationRegistry;
import org.eclipse.jface.fieldassist.IContentProposal;
import org.eclipse.jface.fieldassist.IControlContentAdapter;
import org.eclipse.jface.fieldassist.SimpleContentProposalProvider;
import org.eclipse.jface.preference.PreferenceConverter;
import org.eclipse.jface.resource.ColorDescriptor;
import org.eclipse.jface.resource.ColorRegistry;
import org.eclipse.jface.resource.DeviceResourceException;
import org.eclipse.jface.resource.FontRegistry;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.resource.LocalResourceManager;
import org.eclipse.jface.resource.ResourceManager;
import org.eclipse.jface.util.OpenStrategy;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.wizard.ProgressMonitorPart;
import org.eclipse.jface.wizard.Wizard;
import org.eclipse.jface.wizard.WizardDialog;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.SWT;
import org.eclipse.swt.SWTError;
import org.eclipse.swt.SWTException;
import org.eclipse.swt.accessibility.ACC;
import org.eclipse.swt.accessibility.AccessibleAdapter;
import org.eclipse.swt.accessibility.AccessibleEvent;
import org.eclipse.swt.custom.CLabel;
import org.eclipse.swt.dnd.Clipboard;
import org.eclipse.swt.events.DragDetectEvent;
import org.eclipse.swt.events.DragDetectListener;
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.graphics.Color;
import org.eclipse.swt.graphics.Device;
import org.eclipse.swt.graphics.Drawable;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.FontData;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.ImageData;
import org.eclipse.swt.graphics.ImageLoader;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.graphics.Region;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.program.Program;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.FileDialog;
import org.eclipse.swt.widgets.Item;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.Monitor;
import org.eclipse.swt.widgets.ScrollBar;
import org.eclipse.swt.widgets.Scrollable;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Spinner;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.Text;
import org.eclipse.swt.widgets.ToolItem;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeItem;
import org.eclipse.swt.widgets.Widget;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IEditorReference;
import org.eclipse.ui.IViewPart;
import org.eclipse.ui.IViewReference;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.themes.ITheme;
import org.rssowl.core.Owl;
import org.rssowl.core.connection.MonitorCanceledException;
import org.rssowl.core.internal.persist.pref.DefaultPreferences;
import org.rssowl.core.persist.IBookMark;
import org.rssowl.core.persist.IFolder;
import org.rssowl.core.persist.ILabel;
import org.rssowl.core.persist.IMark;
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.IFolderDAO;
import org.rssowl.core.persist.dao.IPreferenceDAO;
import org.rssowl.core.persist.pref.IPreferenceScope;
import org.rssowl.core.persist.reference.FolderReference;
import org.rssowl.core.persist.service.PersistenceException;
import org.rssowl.core.util.CoreUtils;
import org.rssowl.core.util.Pair;
import org.rssowl.core.util.StringUtils;
import org.rssowl.core.util.SyncUtils;
import org.rssowl.ui.internal.dialogs.CustomWizardDialog;
import org.rssowl.ui.internal.dialogs.LoginDialog;
import org.rssowl.ui.internal.editors.browser.WebBrowserInput;
import org.rssowl.ui.internal.editors.browser.WebBrowserView;
import org.rssowl.ui.internal.editors.feed.FeedView;
import org.rssowl.ui.internal.editors.feed.FeedViewInput;
import org.rssowl.ui.internal.editors.feed.PerformAfterInputSet;
import org.rssowl.ui.internal.util.ContentAssistAdapter;
import org.rssowl.ui.internal.util.EditorUtils;
import org.rssowl.ui.internal.views.explorer.BookMarkExplorer;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URI;
import java.text.DateFormat;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collection;
import java.util.Collections;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
/**
* Central Facade for UI-related tasks.
*
* @author bpasero
*/
public class OwlUI {
/** Top-Level Menu ID for "Tools" */
public static final String M_TOOLS = "tools"; //$NON-NLS-1$
/** Top-Level Menu ID for "Mark" */
public static final String M_MARK = "mark"; //$NON-NLS-1$
/** Top-Level Menu ID for "Open" */
public static final String M_OPEN = "open"; //$NON-NLS-1$
/** Default */
public static final ImageDescriptor UNKNOWN = Activator.getImageDescriptor("icons/obj16/default.gif"); //$NON-NLS-1$
/** Folder */
public static final ImageDescriptor FOLDER = Activator.getImageDescriptor("icons/obj16/folder.gif"); //$NON-NLS-1$
/** Folder with new News */
public static final ImageDescriptor FOLDER_NEW = Activator.getImageDescriptor("icons/obj16/folder_new.gif"); //$NON-NLS-1$
/** Bookmark Set */
public static final ImageDescriptor BOOKMARK_SET = Activator.getImageDescriptor("icons/obj16/bkmrk_set.gif"); //$NON-NLS-1$
/** BookMark */
public static final ImageDescriptor BOOKMARK = Activator.getImageDescriptor("icons/obj16/bookmark.gif"); //$NON-NLS-1$
/** BookMark (Error) */
public static final ImageDescriptor BOOKMARK_ERROR = Activator.getImageDescriptor("icons/obj16/bkmrk_error.gif"); //$NON-NLS-1$
/** NewsBin */
public static final ImageDescriptor NEWSBIN = Activator.getImageDescriptor("icons/obj16/newsbin.gif"); //$NON-NLS-1$
/** NewsBin (New) */
public static final ImageDescriptor NEWSBIN_NEW = Activator.getImageDescriptor("icons/obj16/newsbin_new.gif"); //$NON-NLS-1$
/** NewsBin (Empty) */
public static final ImageDescriptor NEWSBIN_EMPTY = Activator.getImageDescriptor("icons/obj16/newsbin_empty.gif"); //$NON-NLS-1$
/** SearchMark */
public static final ImageDescriptor SEARCHMARK = Activator.getImageDescriptor("icons/obj16/searchmark.gif"); //$NON-NLS-1$
/** SearchMark (New) */
public static final ImageDescriptor SEARCHMARK_NEW = Activator.getImageDescriptor("icons/obj16/searchmark_new.gif"); //$NON-NLS-1$
/** SearchMark (Empty) */
public static final ImageDescriptor SEARCHMARK_EMPTY = Activator.getImageDescriptor("icons/obj16/searchmark_empty.gif"); //$NON-NLS-1$
/** Group */
public static final ImageDescriptor GROUP = Activator.getImageDescriptor("icons/obj16/group.gif"); //$NON-NLS-1$
/** News: Unread */
public static final ImageDescriptor NEWS_STATE_UNREAD = Activator.getImageDescriptor("icons/obj16/news_unread.gif"); //$NON-NLS-1$
/** News: Read */
public static final ImageDescriptor NEWS_STATE_READ = Activator.getImageDescriptor("icons/obj16/news_read.gif"); //$NON-NLS-1$
/** News: New */
public static final ImageDescriptor NEWS_STATE_NEW = Activator.getImageDescriptor("icons/obj16/news_new.gif"); //$NON-NLS-1$
/** News: Updated */
public static final ImageDescriptor NEWS_STATE_UPDATED = Activator.getImageDescriptor("icons/obj16/news_updated.gif"); //$NON-NLS-1$
/** News: Pin */
public static final ImageDescriptor NEWS_PIN = Activator.getImageDescriptor("icons/obj16/news_pin.gif"); //$NON-NLS-1$
/** News: Pinned */
public static final ImageDescriptor NEWS_PINNED = Activator.getImageDescriptor("icons/obj16/news_pinned.gif"); //$NON-NLS-1$
/** Tray Icon: Not Teasing */
public static final ImageDescriptor TRAY_OWL = Activator.getImageDescriptor("icons/elcl16/trayowl.png"); //$NON-NLS-1$
/** Tray Icon: Teasing */
public static final ImageDescriptor TRAY_OWL_TEASING = Activator.getImageDescriptor("icons/elcl16/trayowl_tease.png"); //$NON-NLS-1$
/** Info */
public static final ImageDescriptor INFO = Activator.getImageDescriptor("icons/obj16/info.gif"); //$NON-NLS-1$
/** Warning */
public static final ImageDescriptor WARNING = Activator.getImageDescriptor("icons/obj16/warning.gif"); //$NON-NLS-1$
/** Error */
public static final ImageDescriptor ERROR = Activator.getImageDescriptor("icons/obj16/error.gif"); //$NON-NLS-1$
/** Attachment */
public static final ImageDescriptor ATTACHMENT = Activator.getImageDescriptor("icons/obj16/attachment.gif"); //$NON-NLS-1$
/** Columns */
public static final ImageDescriptor COLUMNS = Activator.getImageDescriptor("icons/etool16/columns.gif"); //$NON-NLS-1$
/** Share */
public static final ImageDescriptor SHARE = Activator.getImageDescriptor("icons/elcl16/share.gif"); //$NON-NLS-1$
/** Filter */
public static final ImageDescriptor FILTER = Activator.getImageDescriptor("icons/etool16/filter.gif"); //$NON-NLS-1$
/** Archive */
public static final ImageDescriptor ARCHIVE = Activator.getImageDescriptor("icons/etool16/archive.gif"); //$NON-NLS-1$
/** Archive (New) */
public static final ImageDescriptor ARCHIVE_NEW = Activator.getImageDescriptor("icons/obj16/archive_new.gif"); //$NON-NLS-1$
/** Archive (Disabled) */
public static final ImageDescriptor ARCHIVE_DISABLED = Activator.getImageDescriptor("icons/dtool16/archive.gif"); //$NON-NLS-1$
/** Group Foreground Color */
public static final RGB GROUP_FG_COLOR = new RGB(0, 0, 128);
/** Group Background Color (non Custom Owner Drawn) */
public static final RGB GROUP_BG_COLOR = new RGB(235, 235, 235);
/** Group Gradient Foreground Color */
public static final RGB GROUP_GRADIENT_FG_COLOR = new RGB(250, 250, 250);
/** Group Gradient Background Color */
public static final RGB GROUP_GRADIENT_BG_COLOR = new RGB(220, 220, 220);
/** Group Gradient End Color */
public static final RGB GROUP_GRADIENT_END_COLOR = new RGB(200, 200, 200);
/** Minimum width of Dialogs in Dialog Units */
public static final int MIN_DIALOG_WIDTH_DLU = 320;
/** News-Text Font Id */
public static final String NEWS_TEXT_FONT_ID = "org.rssowl.ui.NewsTextFont"; //$NON-NLS-1$
/** Headlines Font Id */
public static final String HEADLINES_FONT_ID = "org.rssowl.ui.HeadlinesFont"; //$NON-NLS-1$
/** BookMark Explorer Font Id */
public static final String BKMRK_EXPLORER_FONT_ID = "org.rssowl.ui.BookmarkExplorerFont"; //$NON-NLS-1$
/** Notification Popup Font Id */
public static final String NOTIFICATION_POPUP_FONT_ID = "org.rssowl.ui.NotificationPopupFont"; //$NON-NLS-1$
/** Dialog Font Id */
public static final String DIALOG_FONT_ID = "org.eclipse.jface.dialogfont"; //$NON-NLS-1$
/** Sticky Background Color */
public static final String STICKY_BG_COLOR_ID = "org.rssowl.ui.StickyBGColor"; //$NON-NLS-1$
/** Search Highlight Background Color */
public static final String SEARCH_HIGHLIGHT_BG_COLOR_ID = "org.rssowl.ui.SearchHighlightBGColor"; //$NON-NLS-1$
/** News Background Color */
public static final String NEWS_LIST_BG_COLOR_ID = "org.rssowl.ui.NewsListBackgroundColor"; //$NON-NLS-1$
/** Link Color */
public static final String LINK_FG_COLOR_ID = "org.rssowl.ui.LinkFGColor"; //$NON-NLS-1$
/* ID of the High Contrast Theme */
private static final String HIGH_CONTRAST_THEME = "org.eclipse.ui.ide.systemDefault"; //$NON-NLS-1$
/* Used to cache Image-Descriptors for Favicons */
private static final Map<Long, ImageDescriptor> FAVICO_CACHE = new HashMap<Long, ImageDescriptor>();
/* Used to cache Image-Descriptors obtained from a file-path */
private static final Map<String, ImageDescriptor> DESCRIPTOR_CACHE = new HashMap<String, ImageDescriptor>();
/* Used to cache the path of Images used in the embedded Browser */
private static final Map<String, String> fgImageUriMap = new ConcurrentHashMap<String, String>();
/* Name of Folder for storing Icons */
private static final String ICONS_FOLDER = "icons"; //$NON-NLS-1$
/* Shared Clipboard instance */
private static Clipboard fgClipboard;
/* Cache the OSTheme once retrieved */
private static OSTheme fgCachedOSTheme;
/* Workaround for unknown Date Width */
private static int DATE_WIDTH = -1;
/* Workaround for unknown State Width */
private static int STATE_WIDTH = -1;
/* Default News Text Font Height */
private static final int DEFAULT_NEWS_TEXT_FONT_HEIGHT = 10;
/* System Properties for Date Format */
private static final String SHORT_DATE_FORMAT_PROPERTY = "shortDateFormat"; //$NON-NLS-1$
private static final String LONG_DATE_FORMAT_PROPERTY = "longDateFormat"; //$NON-NLS-1$
private static final String SHORT_TIME_FORMAT_PROPERTY = "shortTimeFormat"; //$NON-NLS-1$
/* Packed Wizard Width per OS (in DLUs) */
private static final int WINDOWS_PACKED_WIZARD_WIDTH = 380;
private static final int LINUX_PACKED_WIZARD_WIDTH = 370;
private static final int MAC_PACKED_WIZARD_WIDTH = 300;
/* Map Common Label Colors to RGB Values */
private static final Map<String, RGB> fgMapCommonColorToRGB = new HashMap<String, RGB>();
/* Map Common Mime Types to Extensions (used for Attachments) */
private static final Map<String, String> fgMapMimeToExtension = new HashMap<String, String>();
static {
/* Audio */
fgMapMimeToExtension.put("audio/mpeg", "mp3"); //$NON-NLS-1$ //$NON-NLS-2$
fgMapMimeToExtension.put("audio/mpeg3", "mp3"); //$NON-NLS-1$ //$NON-NLS-2$
fgMapMimeToExtension.put("audio/x-mpeg3", "mp3"); //$NON-NLS-1$ //$NON-NLS-2$
fgMapMimeToExtension.put("audio/mpeg4", "mp4"); //$NON-NLS-1$ //$NON-NLS-2$
fgMapMimeToExtension.put("audio/x-mpeg4", "mp4"); //$NON-NLS-1$ //$NON-NLS-2$
fgMapMimeToExtension.put("audio/aac", "aac"); //$NON-NLS-1$ //$NON-NLS-2$
fgMapMimeToExtension.put("audio/aacp", "aac"); //$NON-NLS-1$ //$NON-NLS-2$
/* Image */
fgMapMimeToExtension.put("image/bmp", "bmp"); //$NON-NLS-1$ //$NON-NLS-2$
fgMapMimeToExtension.put("image/x-windows-bmp", "bmp"); //$NON-NLS-1$ //$NON-NLS-2$
fgMapMimeToExtension.put("image/gif", "gif"); //$NON-NLS-1$ //$NON-NLS-2$
fgMapMimeToExtension.put("image/jpeg", "jpg"); //$NON-NLS-1$ //$NON-NLS-2$
fgMapMimeToExtension.put("image/pjpeg", "jpg"); //$NON-NLS-1$ //$NON-NLS-2$
fgMapMimeToExtension.put("image/png", "png"); //$NON-NLS-1$ //$NON-NLS-2$
fgMapMimeToExtension.put("image/x-quicktime", "qti"); //$NON-NLS-1$ //$NON-NLS-2$
/* Video */
fgMapMimeToExtension.put("video/x-ms-asf", "asd"); //$NON-NLS-1$ //$NON-NLS-2$
fgMapMimeToExtension.put("application/x-troff-msvideo", "avi"); //$NON-NLS-1$ //$NON-NLS-2$
fgMapMimeToExtension.put("video/avi", "avi"); //$NON-NLS-1$ //$NON-NLS-2$
fgMapMimeToExtension.put("video/msvideo", "avi"); //$NON-NLS-1$ //$NON-NLS-2$
fgMapMimeToExtension.put("video/x-msvideo", "avi"); //$NON-NLS-1$ //$NON-NLS-2$
fgMapMimeToExtension.put("video/x-flv", "flv"); //$NON-NLS-1$ //$NON-NLS-2$
fgMapMimeToExtension.put("video/quicktime", "mov"); //$NON-NLS-1$ //$NON-NLS-2$
/* Application */
fgMapMimeToExtension.put("application/msword", "doc"); //$NON-NLS-1$ //$NON-NLS-2$
fgMapMimeToExtension.put("application/pdf", "pdf"); //$NON-NLS-1$ //$NON-NLS-2$
fgMapMimeToExtension.put("application/rtf", "rtf"); //$NON-NLS-1$ //$NON-NLS-2$
fgMapMimeToExtension.put("text/richtext", "rtf"); //$NON-NLS-1$ //$NON-NLS-2$
fgMapMimeToExtension.put("application/x-rtf", "rtf"); //$NON-NLS-1$ //$NON-NLS-2$
/* Common Colors to RGB */
fgMapCommonColorToRGB.put("0,0,0", new RGB(0, 0, 0)); // "Black",//$NON-NLS-1$
fgMapCommonColorToRGB.put("124,10,2", new RGB(124, 10, 2)); // "Barn Red",//$NON-NLS-1$
fgMapCommonColorToRGB.put("163,21,2", new RGB(163, 21, 2)); // "Salem Red",//$NON-NLS-1$
fgMapCommonColorToRGB.put("214,148,99", new RGB(214, 148, 99)); // "Salmon",//$NON-NLS-1$
fgMapCommonColorToRGB.put("200,118,10", new RGB(200, 118, 10)); // "Pumpkin",//$NON-NLS-1$
fgMapCommonColorToRGB.put("240,177,12", new RGB(240, 177, 12)); // "Marigold Yellow",//$NON-NLS-1$
fgMapCommonColorToRGB.put("209,161,17", new RGB(209, 161, 17)); // "Mustard",//$NON-NLS-1$
fgMapCommonColorToRGB.put("136,128,54", new RGB(136, 128, 54)); // "Bayberry Green",//$NON-NLS-1$
fgMapCommonColorToRGB.put("129,150,93", new RGB(129, 150, 93)); // "Tavern Green",//$NON-NLS-1$
fgMapCommonColorToRGB.put("82,92,58", new RGB(82, 92, 58)); // "Lexington Green",//$NON-NLS-1$
fgMapCommonColorToRGB.put("126,135,130", new RGB(126, 135, 130)); // "Sea Green",//$NON-NLS-1$
fgMapCommonColorToRGB.put("111,121,174", new RGB(111, 121, 174)); // "Federal Blue",//$NON-NLS-1$
fgMapCommonColorToRGB.put("92,101,126", new RGB(92, 101, 126)); // "Soldier Blue",//$NON-NLS-1$
fgMapCommonColorToRGB.put("144,152,163", new RGB(144, 152, 163)); // "Slate",//$NON-NLS-1$
fgMapCommonColorToRGB.put("25,16,17", new RGB(25, 16, 17)); // "Pitch Black",//$NON-NLS-1$
fgMapCommonColorToRGB.put("82,66,41", new RGB(82, 66, 41)); // "Driftwood",//$NON-NLS-1$
fgMapCommonColorToRGB.put("82,16,0", new RGB(82, 16, 0)); // "Chocolate Brown" //$NON-NLS-1$
fgMapCommonColorToRGB.put("255,0,0", new RGB(255, 0, 0)); // "Red" //$NON-NLS-1$
fgMapCommonColorToRGB.put("0,255,0", new RGB(0, 255, 0)); // "Greeen" //$NON-NLS-1$
fgMapCommonColorToRGB.put("0,0,255", new RGB(0, 0, 255)); // "Blue" //$NON-NLS-1$
}
/** An enumeration of Operating System Themes */
public enum OSTheme {
/** Windows XP Blue */
WINDOWS_BLUE,
/** Windows XP Silver */
WINDOWS_SILVER,
/** Windows XP Olive */
WINDOWS_OLIVE,
/** Windows Classic */
WINDOWS_CLASSIC,
/** High Contrast */
HIGH_CONTRAST,
/** Any other Theme */
OTHER
}
/** An enumeration of Open Modes when opening something in the Feed View */
public enum FeedViewOpenMode {
/** Force to Activate the Feed */
FORCE_ACTIVATE,
/** Ignore Feed if already opened */
IGNORE_ALREADY_OPENED,
/** Ignore Tab reuse for Feeds */
IGNORE_REUSE;
}
/** Supported Feedview Layouts */
public enum Layout {
CLASSIC(Messages.OwlUI_CLASSIC_LAYOUT),
VERTICAL(Messages.OwlUI_VERTICAL_LAYOUT),
LIST(Messages.OwlUI_LIST_LAYOUT),
NEWSPAPER(Messages.OwlUI_NEWSPAPER_LAYOUT),
HEADLINES(Messages.OwlUI_HEADLINES_LAYOUT);
private final String fName;
private Layout(String name) {
fName = name;
}
/**
* @return the name of this layout option.
*/
public String getName() {
return fName;
}
}
/** Supported Page Sizes for Newspaper/Headlines Layout */
public enum PageSize {
TEN(Messages.OwlUI_T_ARTICLES, 10),
TWENTY_FIVE(Messages.OwlUI_TF_ARTICLES, 25),
FIFTY(Messages.OwlUI_F_ARTICLES, 50),
HUNDRED(Messages.OwlUI_H_ARTICLES, 100),
NO_PAGING(Messages.OwlUI_ALL_ARTICLES, 0);
private final String fName;
private final int fPageSize;
private PageSize(String name, int pageSize) {
fName = name;
fPageSize = pageSize;
}
/**
* @return the name of the page size option.
*/
public String getName() {
return fName;
}
/**
* @return the page size.
*/
public int getPageSize() {
return fPageSize;
}
/**
* @param pageSize the configured page size.
* @return the matching {@link PageSize} value from the enum or
* <code>NO_PAGING</code> if none.
*/
public static PageSize from(int pageSize) {
switch (pageSize) {
case 10:
return TEN;
case 25:
return TWENTY_FIVE;
case 50:
return FIFTY;
case 100:
return HUNDRED;
}
return NO_PAGING;
}
}
/* Helper to ensure favicons cause no errors if corrupt */
private static class FavIconImageDescriptor extends ImageDescriptor {
private final ImageDescriptor fDescriptor;
private final File fFaviconFile;
private FavIconImageDescriptor(File faviconFile, ImageDescriptor descriptor) {
Assert.isNotNull(faviconFile);
Assert.isNotNull(descriptor);
fFaviconFile = faviconFile;
fDescriptor = descriptor;
}
/*
* @see org.eclipse.jface.resource.ImageDescriptor#getImageData()
*/
@Override
public ImageData getImageData() {
return fDescriptor.getImageData();
}
/*
* @see org.eclipse.jface.resource.ImageDescriptor#createImage(boolean, org.eclipse.swt.graphics.Device)
*/
@Override
public Image createImage(boolean returnMissingImageOnError, Device device) {
try {
return internalCreateImage(returnMissingImageOnError, device);
} catch (SWTException e) {
//Fallback to default Image
} catch (SWTError error) {
//Fallback to default Image
}
return BOOKMARK.createImage(returnMissingImageOnError, device);
}
private Image internalCreateImage(boolean returnMissingImageOnError, Device device) {
try {
if (Application.IS_LINUX) //Use native loading on Linux to support alpha in ICO
return new Image(device, fFaviconFile.toString());
ImageLoader loader = new ImageLoader();
ImageData[] datas = loader.load(fFaviconFile.toString());
if (datas != null && datas.length > 0)
return new Image(device, datas[0]);
} catch (SWTException e) {
//Fallback to alternative method to load Image
} catch (SWTError error) {
//Fallback to alternative method to load Image
}
return fDescriptor.createImage(returnMissingImageOnError, device);
}
/*
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(Object obj) {
return fDescriptor.equals(obj);
}
/*
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
return fDescriptor.hashCode();
}
/*
* @see org.eclipse.jface.resource.ImageDescriptor#destroyResource(java.lang.Object)
*/
@Override
public void destroyResource(Object previouslyCreatedObject) {
fDescriptor.destroyResource(previouslyCreatedObject);
}
}
/**
* Returns the <code>OSTheme</code> that is currently being used.
*
* @param display An instance of the SWT <code>Display</code> used for
* determining the used theme.
* @return Returns the <code>OSTheme</code> that is currently being used.
*/
public static OSTheme getOSTheme(Display display) {
/* Check Cached version first */
if (fgCachedOSTheme != null)
return fgCachedOSTheme;
ITheme currentTheme = PlatformUI.getWorkbench().getThemeManager().getCurrentTheme();
if (HIGH_CONTRAST_THEME.equals(currentTheme.getId())) {
fgCachedOSTheme = OSTheme.HIGH_CONTRAST;
return fgCachedOSTheme;
}
RGB widgetBackground = display.getSystemColor(SWT.COLOR_WIDGET_BACKGROUND).getRGB();
RGB listSelection = display.getSystemColor(SWT.COLOR_LIST_SELECTION).getRGB();
/* Theme: Windows Blue */
if (widgetBackground.equals(new RGB(236, 233, 216)) && listSelection.equals(new RGB(49, 106, 197)))
fgCachedOSTheme = OSTheme.WINDOWS_BLUE;
/* Theme: Windows Classic */
else if (widgetBackground.equals(new RGB(212, 208, 200)) && listSelection.equals(new RGB(10, 36, 106)))
fgCachedOSTheme = OSTheme.WINDOWS_CLASSIC;
/* Theme: Windows Silver */
else if (widgetBackground.equals(new RGB(224, 223, 227)) && listSelection.equals(new RGB(178, 180, 191)))
fgCachedOSTheme = OSTheme.WINDOWS_SILVER;
/* Theme: Windows Olive */
else if (widgetBackground.equals(new RGB(236, 233, 216)) && listSelection.equals(new RGB(147, 160, 112)))
fgCachedOSTheme = OSTheme.WINDOWS_OLIVE;
/* Any other Theme */
else
fgCachedOSTheme = OSTheme.OTHER;
return fgCachedOSTheme;
}
/**
* @return <code>true</code> if the display settings is set to high contrast
* mode and <code>false</code> otherwise.
*/
public static boolean isHighContrast() {
return getOSTheme(Display.getDefault()) == OSTheme.HIGH_CONTRAST;
}
/**
* Get the shared instance of <code>Clipboard</code>.
*
* @return the shared instance of <code>Clipboard</code>.
*/
public static Clipboard getClipboard() {
return getClipboard(PlatformUI.getWorkbench().getDisplay());
}
/**
* Get the shared instance of <code>Clipboard</code>.
*
* @param display the {@link Display} the clipboard is operating on.
* @return the shared instance of <code>Clipboard</code>.
*/
public static Clipboard getClipboard(Display display) {
if (fgClipboard == null)
fgClipboard = new Clipboard(display);
return fgClipboard;
}
/**
* @param path
* @return ImageDescriptor
*/
public static ImageDescriptor getImageDescriptor(String path) {
return getImageDescriptor(Activator.PLUGIN_ID, path);
}
/**
* @param pluginId
* @param path
* @return ImageDescriptor
*/
public static ImageDescriptor getImageDescriptor(String pluginId, String path) {
ImageDescriptor desc = DESCRIPTOR_CACHE.get(pluginId + path);
if (desc == null) {
desc = Activator.getImageDescriptor(pluginId, path);
DESCRIPTOR_CACHE.put(pluginId + path, desc);
}
return desc;
}
/**
* @param manager
* @param descriptor
* @return Image
*/
public static Image getImage(ResourceManager manager, ImageDescriptor descriptor) {
try {
return manager.createImage(descriptor);
} catch (DeviceResourceException e) {
return getDefaultImage(manager);
} catch (SWTException e) {
return getDefaultImage(manager);
}
}
/* Returns the default Image or NULL if unable to create */
private static Image getDefaultImage(ResourceManager manager) {
try {
return manager.createImage(UNKNOWN);
} catch (DeviceResourceException e1) {
return null; // Should not happen
}
}
/**
* @param manager
* @param path
* @return Image
*/
public static Image getImage(ResourceManager manager, String path) {
return getImage(manager, getImageDescriptor(path));
}
/**
* @param owner
* @param path
* @return Image
*/
public static Image getImage(Control owner, String path) {
LocalResourceManager manager = new LocalResourceManager(JFaceResources.getResources(), owner);
return getImage(manager, path);
}
/**
* @param owner
* @param descriptor
* @return Image
*/
public static Image getImage(Control owner, ImageDescriptor descriptor) {
LocalResourceManager manager = new LocalResourceManager(JFaceResources.getResources(), owner);
return getImage(manager, descriptor);
}
/**
* @param path the path to the image as absolute path from the plugin root.
* @param name the name of the image.
* @return an {@link URI} to a file where the image has been saved to.
*/
public static String getImageUri(String path, String name) {
/* Check Cache */
String imgUri = fgImageUriMap.get(path);
if (imgUri != null)
return imgUri;
/* Check Filesystem */
File imgFile = getImageFile(name);
if (imgFile.exists()) {
imgUri = getImageUri(imgFile);
fgImageUriMap.put(path, imgUri);
return imgUri;
}
/* Copy to Filesystem */
try {
CoreUtils.copy(OwlUI.class.getResourceAsStream(path), new FileOutputStream(imgFile));
imgUri = getImageUri(imgFile);
fgImageUriMap.put(path, imgUri);
return imgUri;
} catch (IOException e) {
Activator.getDefault().logError(e.getMessage(), e);
}
return null;
}
private static String getImageUri(File file) {
URI uri = file.toURI();
String s = uri.toString();
return s.replaceFirst("/", "///"); //$NON-NLS-1$ //$NON-NLS-2$
}
/**
* @param manager
* @param rgb
* @return Color
*/
public static Color getColor(ResourceManager manager, RGB rgb) {
try {
return manager.createColor(rgb);
} catch (DeviceResourceException e) {
return manager.getDevice().getSystemColor(SWT.COLOR_BLACK);
}
}
/**
* @param manager
* @param descriptor
* @return Color
*/
public static Color getColor(ResourceManager manager, ColorDescriptor descriptor) {
try {
return manager.createColor(descriptor);
} catch (DeviceResourceException e) {
return manager.getDevice().getSystemColor(SWT.COLOR_BLACK);
}
}
/**
* @param resources
* @param label
* @return Color
*/
public static Color getColor(ResourceManager resources, ILabel label) {
RGB rgb = getRGB(label);
return getColor(resources, rgb);
}
/**
* @param label
* @return RGB
*/
public static RGB getRGB(ILabel label) {
return getRGB(label.getColor());
}
/**
* @param rgb
* @return RGB
*/
public static RGB getRGB(String rgb) {
if (!StringUtils.isSet(rgb))
return null;
RGB commonRGB = fgMapCommonColorToRGB.get(rgb);
if (commonRGB != null)
return commonRGB;
String color[] = rgb.split(","); //$NON-NLS-1$
return new RGB(Integer.parseInt(color[0]), Integer.parseInt(color[1]), Integer.parseInt(color[2]));
}
/**
* @param rgb
* @return String
*/
public static String toString(RGB rgb) {
return rgb.red + "," + rgb.green + "," + rgb.blue; //$NON-NLS-1$ //$NON-NLS-2$
}
/**
* @param key
* @return Font
*/
public static Font getFont(String key) {
return JFaceResources.getFontRegistry().get(key);
}
/**
* @param key
* @return Font
*/
public static Font getBold(String key) {
return JFaceResources.getFontRegistry().getBold(key);
}
/**
* @param key
* @return Font
*/
public static Font getItalic(String key) {
return JFaceResources.getFontRegistry().getItalic(key);
}
/**
* @param key
* @param style
* @return Font
*/
public static Font getThemeFont(String key, int style) {
FontRegistry fontRegistry = PlatformUI.getWorkbench().getThemeManager().getCurrentTheme().getFontRegistry();
if (fontRegistry != null) {
if (style == SWT.NORMAL)
return fontRegistry.get(key);
else if ((style & SWT.BOLD) != 0)
return fontRegistry.getBold(key);
else if ((style & SWT.ITALIC) != 0)
return fontRegistry.getItalic(key);
}
return getFont(key);
}
/**
* @param key
* @param manager
* @param defaultColor
* @return Font
*/
public static Color getThemeColor(String key, ResourceManager manager, RGB defaultColor) {
ColorRegistry colorRegistry = PlatformUI.getWorkbench().getThemeManager().getCurrentTheme().getColorRegistry();
if (colorRegistry != null)
return getColor(manager, colorRegistry.getColorDescriptor(key));
return getColor(manager, defaultColor);
}
/**
* @param key
* @param defaultRGB
* @return Font
*/
public static RGB getThemeRGB(String key, RGB defaultRGB) {
ColorRegistry colorRegistry = PlatformUI.getWorkbench().getThemeManager().getCurrentTheme().getColorRegistry();
if (colorRegistry != null)
return colorRegistry.getRGB(key);
return defaultRGB;
}
/**
* @param drawable
* @param text
* @param font
* @return The size of the Text as Point.
*/
public static Point getTextSize(Drawable drawable, Font font, String text) {
GC gc = new GC(drawable);
gc.setFont(font);
Point p = gc.textExtent(text);
gc.dispose();
return p;
}
/**
* @param bookmark
* @return ImageDescriptor
*/
public static ImageDescriptor getFavicon(IBookMark bookmark) {
if (bookmark.getId() == null)
return null;
/* 1.) Check if ImageDescriptor exists in Memory */
ImageDescriptor descriptor = FAVICO_CACHE.get(bookmark.getId());
if (descriptor != null)
return descriptor;
/* 2.) Check if ImageDescriptor exists in File System */
File favicon = getImageFile(bookmark.getId());
if (favicon != null && favicon.exists()) {
try {
descriptor = new FavIconImageDescriptor(favicon, ImageDescriptor.createFromURL(favicon.toURI().toURL()));
FAVICO_CACHE.put(bookmark.getId(), descriptor);
return descriptor;
} catch (MalformedURLException e) {
Activator.getDefault().logError(e.getMessage(), e);
}
}
return null;
}
/**
* @param id
*/
public static void deleteImage(long id) {
/* Delete from Cache */
FAVICO_CACHE.remove(id);
/* Delete from Disk */
File file = getImageFile(id);
if (file != null && file.exists())
file.delete();
}
/**
* Deletes all stored icons from the org.rssowl.ui icons folder.
*/
public static void clearFavicons() {
Activator activator = Activator.getDefault();
if (activator == null)
return;
IPath path = new Path(activator.getStateLocation().toOSString());
path = path.append(ICONS_FOLDER);
File iconsFolder = new File(path.toOSString());
if (!iconsFolder.exists())
return;
File[] files = iconsFolder.listFiles();
for (File file : files) {
if (file.getName().endsWith(".ico")) //$NON-NLS-1$
file.delete();
}
}
/**
* @param id
* @param bytes
* @param defaultImage
* @param wHint
* @param hHint
*/
public static void storeImage(long id, byte[] bytes, ImageDescriptor defaultImage, int wHint, int hHint) {
Assert.isNotNull(defaultImage);
Assert.isLegal(wHint > 0);
Assert.isLegal(hHint > 0);
ImageData imgData = null;
/* Bytes Provided */
if (bytes != null && bytes.length > 0) {
ByteArrayInputStream inS = null;
try {
inS = new ByteArrayInputStream(bytes);
ImageLoader loader = new ImageLoader();
ImageData[] imageDatas = loader.load(inS);
/* Look for the Icon with the best quality */
if (imageDatas != null)
imgData = getBestQuality(imageDatas, wHint, hHint);
} catch (SWTException e) {
/* Ignore any Image-Format exceptions */
} finally {
if (inS != null) {
try {
inS.close();
} catch (IOException e) {
if (!(e instanceof MonitorCanceledException))
Activator.getDefault().logError(e.getMessage(), e);
}
}
}
}
/* Use default Image if img-data is null */
if (imgData == null)
imgData = defaultImage.getImageData();
/* Save Image into Cache-Area on File-System */
if (imgData != null) {
File imageFile = getImageFile(id);
if (imageFile == null)
return;
/* Scale if required */
if (imgData.width != 16 || imgData.height != 16)
imgData = imgData.scaledTo(16, 16);
/* Try using native Image Format */
try {
if (storeImage(imgData, imageFile, imgData.type))
return;
} catch (SWTException e) {
/* Ignore any Image-Format exceptions */
}
/* Try using various other Image-Formats */
int formats[] = new int[] { SWT.IMAGE_PNG, SWT.IMAGE_ICO, SWT.IMAGE_GIF, SWT.IMAGE_BMP };
for (int format : formats) {
if (format != imgData.type) {
try {
if (storeImage(imgData, imageFile, format))
return;
} catch (SWTException e) {
/* Ignore any Image-Format exceptions */
}
}
}
}
}
/* Returns the ImageData with best Depth or Size */
private static ImageData getBestQuality(ImageData datas[], int wHint, int hHint) {
ImageData bestSize = null;
ImageData bestDepth = null;
int maxDepth = -1;
int maxSize = -1;
/* Foreach Image: Check best Depth */
for (ImageData data : datas) {
if (data.depth > maxDepth) {
maxDepth = data.depth;
bestDepth = data;
}
}
/* Foreach Image: Check best Size */
for (ImageData data : datas) {
/* Only consider best depth */
if (data.depth == maxDepth) {
/* Return if Size matches Hint */
if (data.width == wHint && data.height == hHint)
return data;
/* Otherwise look for bigges */
if (data.width * data.height > maxSize) {
maxSize = data.width * data.height;
bestSize = data;
}
}
}
return (bestDepth != null) ? bestDepth : bestSize;
}
/* Saves the Image to the given File with the given Image-Format */
private static boolean storeImage(ImageData imgData, File file, int format) {
ImageLoader loader = new ImageLoader();
loader.data = new ImageData[] { imgData };
FileOutputStream fOs = null;
try {
fOs = new FileOutputStream(file);
loader.save(fOs, format);
} catch (FileNotFoundException e) {
Activator.getDefault().logError(e.getMessage(), e);
} finally {
if (fOs != null)
try {
fOs.close();
} catch (IOException e) {
Activator.getDefault().logError(e.getMessage(), e);
}
}
return true;
}
private static File getImageFile(String fileName) {
boolean res = false;
Activator activator = Activator.getDefault();
if (activator == null)
return null;
IPath path = new Path(activator.getStateLocation().toOSString());
path = path.append(ICONS_FOLDER);
File root = new File(path.toOSString());
if (!root.exists())
res = root.mkdir();
else
res = true;
path = path.append(fileName);
if (!res)
return null;
return new File(path.toOSString());
}
private static File getImageFile(long id) {
return getImageFile(id + ".ico"); //$NON-NLS-1$
}
/**
* Attempts to find the primary <code>IWorkbenchWindow</code> from the
* PlatformUI facade. Otherwise, returns <code>NULL</code> if none.
*
* @return the primary <code>IWorkbenchWindow</code> from the PlatformUI
* facade or <code>NULL</code> if none.
*/
public static IWorkbenchWindow getPrimaryWindow() {
/* Return the first Window of the Workbench */
IWorkbenchWindow windows[] = PlatformUI.getWorkbench().getWorkbenchWindows();
if (windows.length > 0)
return windows[0];
return null;
}
/**
* Attempts to find the first <code>IWorkbenchWindow</code> from the
* PlatformUI facade. Otherwise, returns <code>NULL</code> if none.
*
* @return the first <code>IWorkbenchWindow</code> from the PlatformUI facade
* or <code>NULL</code> if none.
*/
public static IWorkbenchWindow getWindow() {
/* First try active Window */
IWorkbenchWindow activeWorkbenchWindow = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
if (activeWorkbenchWindow != null)
return activeWorkbenchWindow;
/* Finally try any Window */
IWorkbenchWindow windows[] = PlatformUI.getWorkbench().getWorkbenchWindows();
if (windows.length > 0)
return windows[0];
return null;
}
/**
* Attempts to find the <code>IWorkbenchWindow</code> from the PlatformUI
* facade that is located at where the mouse is pointing at. Otherwise,
* returns <code>NULL</code> if none.
*
* @return the first <code>IWorkbenchWindow</code> from the PlatformUI facade
* that is located at where the mouse is pointing at or <code>NULL</code> if
* none.
*/
public static IWorkbenchWindow getWindowAtCursor() {
/* Get the Control at the Cursor position */
Control cursorControl = Display.getDefault().getCursorControl();
if (cursorControl == null)
return null;
/* Return Window that belongs to Cursor-Shell */
Shell cursorShell = cursorControl.getShell();
IWorkbenchWindow windows[] = PlatformUI.getWorkbench().getWorkbenchWindows();
for (IWorkbenchWindow workbenchWindow : windows) {
if (workbenchWindow.getShell().equals(cursorShell))
return workbenchWindow;
}
return null;
}
/**
* Attempts to find the first <code>IWorkbenchPage</code> from the PlatformUI
* facade. Otherwise, returns <code>NULL</code> if none.
*
* @return the first <code>IWorkbenchPage</code> from the PlatformUI facade or
* <code>NULL</code> if none.
*/
public static IWorkbenchPage getPage() {
IWorkbenchWindow window = getWindow();
return getPage(window);
}
/**
* Attempts to find the first <code>IWorkbenchPage</code> from the PlatformUI
* facade. Otherwise, returns <code>NULL</code> if none.
*
* @param window the {@link IWorkbenchWindow} to search for a
* {@link IWorkbenchPage}.
* @return the first <code>IWorkbenchPage</code> from the PlatformUI facade or
* <code>NULL</code> if none.
*/
public static IWorkbenchPage getPage(IWorkbenchWindow window) {
if (window != null) {
/* First try active Page */
if (window.getActivePage() != null)
return window.getActivePage();
/* Finally try any Page */
IWorkbenchPage[] pages = window.getPages();
if (pages.length > 0)
return pages[0];
}
return null;
}
/**
* Attempts to find the active <code>IWorkbenchPart</code> from the PlatformUI
* facade. Otherwise, returns <code>NULL</code> if none.
*
* @param window the {@link IWorkbenchWindow} to search in.
* @return the active <code>IWorkbenchPart</code> from the PlatformUI facade
* or <code>NULL</code> if none.
*/
public static IWorkbenchPart getActivePart(IWorkbenchWindow window) {
if (window != null) {
/* First try active Page */
if (window.getActivePage() != null)
return window.getActivePage().getActivePart();
/* Finally try any Page */
IWorkbenchPage[] pages = window.getPages();
for (IWorkbenchPage page : pages) {
if (page.getActivePart() != null)
return page.getActivePart();
}
}
return null;
}
/**
* Attempts to return the index of the given workbench window or
* <code>-1</code> if none.
*
* @param window the {@link IWorkbenchWindow} to get the index in the stack of
* windows that are open.
* @return the index of the given workbench window or <code>-1</code> if none.
*/
public static int getWindowIndex(IWorkbenchWindow window) {
if (window != null) {
IWorkbenchWindow[] windows = PlatformUI.getWorkbench().getWorkbenchWindows();
for (int i = 0; i < windows.length; i++)
if (windows[i].equals(window))
return i;
}
return 0;
}
/**
* Attempts to find the <code>IWorkbenchPage</code> from the Workbench-Window
* the mouse is currently over from the PlatformUI facade. Otherwise, returns
* <code>NULL</code> if none.
*
* @return the first <code>IWorkbenchPage</code> from the Workbench-Window the
* mouse is currently over from the PlatformUI facade or <code>NULL</code> if
* none.
*/
public static IWorkbenchPage getPageAtCursor() {
IWorkbenchWindow window = getWindowAtCursor();
if (window != null) {
/* First try active Page */
if (window.getActivePage() != null)
return window.getActivePage();
/* Finally try any Page */
IWorkbenchPage[] pages = window.getPages();
if (pages.length > 0)
return pages[0];
}
return null;
}
/**
* Attempts to find the first active <code>IEditorPart</code> from the
* PlatformUI facade. Otherwise, returns <code>NULL</code> if none.
*
* @return the first active <code>IEditorPart</code> from the PlatformUI
* facade or <code>NULL</code> if none.
*/
public static IEditorPart getActiveEditor() {
IWorkbenchPage page = getPage();
if (page != null)
return page.getActiveEditor();
return null;
}
/**
* @return a list of all editors currently open in the UI as references.
*/
public static List<IEditorReference> getEditorReferences() {
IWorkbenchPage page = getPage();
if (page != null) {
IEditorReference[] references = page.getEditorReferences();
return Arrays.asList(references);
}
return Collections.emptyList();
}
/**
* @return the number of opened feed views (will not trigger editor
* restoring).
*/
public static int getOpenFeedViewCount() {
int count = 0;
List<IEditorReference> editors = getEditorReferences();
for (IEditorReference reference : editors) {
if (FeedView.ID.equals(reference.getId()))
count++;
}
return count;
}
/**
* Attempts to find the first active <code>FeedView</code> from the PlatformUI
* facade. Otherwise, returns <code>NULL</code> if none.
*
* @return the first active <code>FeedView</code> from the PlatformUI facade
* or <code>NULL</code> if none.
*/
public static FeedView getActiveFeedView() {
IWorkbenchPage page = getPage();
if (page != null) {
IEditorPart activeEditor = page.getActiveEditor();
if (activeEditor != null && activeEditor instanceof FeedView)
return (FeedView) activeEditor;
}
return null;
}
/**
* @return the {@link INewsMark} currently showing in the active feed view if
* any or <code>null</code> otherwise.
*/
public static INewsMark getActiveFeedViewNewsMark() {
try {
FeedView activeFeedView = getActiveFeedView();
if (activeFeedView != null) {
FeedViewInput input = (FeedViewInput) activeFeedView.getEditorInput();
return input.getMark();
}
} catch (Error e) {
/* Since this method might be called from any thread, protect fully */
}
return null;
}
/**
* Attempts to find the first active <code>FeedView</code> from the PlatformUI
* facade and then will return the feed view input preferences. Otherwise,
* returns <code>NULL</code> if none.
*
* @return the first active <code>FeedView</code> input preferences from the
* PlatformUI facade or <code>NULL</code> if none.
*/
public static IPreferenceScope getActiveFeedViewPreferences() {
FeedView feedView = getActiveFeedView();
if (feedView != null) {
IEditorInput input = feedView.getEditorInput();
if (input instanceof FeedViewInput) {
FeedViewInput feedViewInput = (FeedViewInput) input;
if (feedViewInput.getMark() != null) {
INewsMark mark = feedViewInput.getMark();
if (mark instanceof FolderNewsMark)
return Owl.getPreferenceService().getEntityScope(((FolderNewsMark) mark).getFolder());
return Owl.getPreferenceService().getEntityScope(feedViewInput.getMark());
}
}
}
return null;
}
/**
* Attempts to find all open <code>FeedView</code>s from the PlatformUI
* facade. Otherwise, returns an empty list if none.
*
* @return all open <code>FeedView</code>s from the PlatformUI facade or an
* empty list if none.
*/
public static List<FeedView> getFeedViews() {
List<FeedView> feedViews = new ArrayList<FeedView>();
List<IEditorReference> references = getEditorReferences();
for (IEditorReference reference : references) {
if (FeedView.ID.equals(reference.getId())) {
IEditorPart editor = reference.getEditor(true);
if (editor instanceof FeedView)
feedViews.add((FeedView) editor);
}
}
return feedViews;
}
/**
* Attempts to find the selection from the first active <code>FeedView</code>
* from the PlatformUI facade. Otherwise, returns
* <code>StructuredSelection.EMPTY</code> if none.
*
* @return the selection from the first active <code>FeedView</code> from the
* PlatformUI facade or <code>StructuredSelection.EMPTY</code> if none.
*/
public static IStructuredSelection getActiveFeedViewSelection() {
FeedView feedview = getActiveFeedView();
if (feedview == null)
return StructuredSelection.EMPTY;
ISelectionProvider selectionProvider = feedview.getSite().getSelectionProvider();
if (selectionProvider == null)
return StructuredSelection.EMPTY;
return (IStructuredSelection) selectionProvider.getSelection();
}
/**
* Attempts to find the selection from the first active <code>Part</code> from
* the PlatformUI facade. Otherwise, returns
* <code>StructuredSelection.EMPTY</code> if none.
*
* @return the selection from the first active <code>Part</code> from the
* PlatformUI facade or <code>StructuredSelection.EMPTY</code> if none.
*/
public static IStructuredSelection getActiveSelection() {
IWorkbenchPage page = getPage();
if (page != null) {
IWorkbenchPart part = page.getActivePart();
if (part != null && part.getSite() != null) {
ISelectionProvider selectionProvider = part.getSite().getSelectionProvider();
if (selectionProvider != null) {
ISelection selection = selectionProvider.getSelection();
if (!selection.isEmpty() && selection instanceof IStructuredSelection)
return (IStructuredSelection) selection;
}
}
}
return StructuredSelection.EMPTY;
}
/**
* Attempts to find the first <code>FeedView</code> from the active Workbench
* Window of the PlatformUI facade. Otherwise, returns <code>NULL</code> if
* none.
*
* @return the first <code>FeedView</code> from the active Workbench Window of
* the PlatformUI facade or <code>NULL</code> if none.
*/
public static FeedView getFirstActiveFeedView() {
IWorkbenchPage page = getPage();
if (page != null) {
/* First try current active editor */
IEditorPart activeEditor = page.getActiveEditor();
if (activeEditor instanceof FeedView)
return (FeedView) activeEditor;
/* Then navigate through all from first to last */
IEditorReference[] editorReferences = page.getEditorReferences();
for (IEditorReference editorReference : editorReferences) {
if (FeedView.ID.equals(editorReference.getId()))
return (FeedView) editorReference.getEditor(true);
}
}
return null;
}
/**
* Attempts to find the first <code>WebBrowserView</code> from the active
* Workbench Window of the PlatformUI facade. Otherwise, returns
* <code>NULL</code> if none.
*
* @return the first <code>WebBrowserView</code> from the active Workbench
* Window of the PlatformUI facade or <code>NULL</code> if none.
*/
public static WebBrowserView getFirstActiveBrowser() {
IWorkbenchPage page = getPage();
if (page != null) {
IEditorReference[] editorReferences = page.getEditorReferences();
for (IEditorReference editorReference : editorReferences) {
try {
if (editorReference.getEditorInput() instanceof WebBrowserInput)
return (WebBrowserView) editorReference.getEditor(true);
} catch (PartInitException e) {
/* Ignore Silently */
}
}
}
return null;
}
/**
* Attempts to find the opened <code>BookMarkExplorer</code> from the
* PlatformUI facade. Otherwise, returns <code>NULL</code> if none.
*
* @return the <code>BookMarkExplorer</code> from the PlatformUI facade or
* <code>NULL</code> if not opened.
*/
public static BookMarkExplorer getOpenedBookMarkExplorer() {
IWorkbenchPage page = getPage();
if (page != null) {
IViewReference[] viewReferences = page.getViewReferences();
for (IViewReference viewRef : viewReferences) {
if (viewRef.getId().equals(BookMarkExplorer.VIEW_ID)) {
IViewPart view = viewRef.getView(true);
if (view instanceof BookMarkExplorer)
return (BookMarkExplorer) view;
}
}
}
return null;
}
/**
* Attempts to find the primary <code>Shell</code> from the PlatformUI facade.
* Otherwise, returns <code>NULL</code> if none.
*
* @return the primary <code>Shell</code> from the PlatformUI facade or
* <code>NULL</code> if none.
*/
public static Shell getPrimaryShell() {
IWorkbenchWindow window = getPrimaryWindow();
if (window != null)
return window.getShell();
return null;
}
/**
* Attempts to find the active <code>Shell</code> from the PlatformUI facade.
* Otherwise, returns <code>NULL</code> if none.
*
* @return the active <code>Shell</code> from the PlatformUI facade or
* <code>NULL</code> if none.
*/
public static Shell getActiveShell() {
IWorkbenchWindow window = getWindow();
if (window != null)
return window.getShell();
return null;
}
/**
* Update the current active window title based on the given array of
* {@link IMark}.
*
* @param input the input that is currently visible in RSSOwl.
*/
public static void updateWindowTitle(IMark input) {
if (input != null)
updateWindowTitle(input.getName());
}
/**
* Update the current active window title based on the given title.
*
* @param title the name of the input that is currently visible in RSSOwl.
*/
public static void updateWindowTitle(String title) {
IWorkbenchWindow window = getWindow();
if (window != null) {
String appTitle = "RSSOwl"; //$NON-NLS-1$
if (StringUtils.isSet(title))
title = NLS.bind(Messages.OwlUI_TITLE, title, appTitle);
else
title = appTitle;
String shellText = window.getShell().getText();
if (shellText == null || !shellText.equals(title))
window.getShell().setText(title);
}
}
/**
* A helper method that can be used to restore the application when its
* minimized.
*
* @param page the workbench page the application is running in.
*/
public static void restoreWindow(IWorkbenchPage page) {
Shell applicationShell = page.getWorkbenchWindow().getShell();
restoreWindow(applicationShell);
}
/**
* A helper method that can be used to restore the application when its
* minimized.
*
* @param applicationShell the main {@link Shell} of the application.
*/
public static void restoreWindow(Shell applicationShell) {
ApplicationWorkbenchWindowAdvisor advisor = ApplicationWorkbenchAdvisor.fgPrimaryApplicationWorkbenchWindowAdvisor;
/* Restore From Tray */
if (advisor != null && advisor.isMinimizedToTray())
advisor.restoreFromTray(applicationShell);
/* Restore from being Minimized */
else if (applicationShell.getMinimized()) {
applicationShell.setMinimized(false);
applicationShell.forceActive();
}
/* Otherwise force Active */
else
applicationShell.forceActive();
}
/**
* @return the current selected {@link IFolder} of the bookmark explorer or
* the parent of the current selected {@link IMark} or <code>null</code> if
* none.
*/
public static IFolder getBookMarkExplorerSelection() {
IWorkbenchPage page = getPage();
if (page != null) {
IViewPart viewPart = page.findView(BookMarkExplorer.VIEW_ID);
if (viewPart != null) {
IStructuredSelection selection = (IStructuredSelection) viewPart.getSite().getSelectionProvider().getSelection();
if (!selection.isEmpty()) {
Object selectedEntity = selection.iterator().next();
if (selectedEntity instanceof IFolder)
return (IFolder) selectedEntity;
else if (selectedEntity instanceof IMark)
return ((IMark) selectedEntity).getParent();
}
}
}
return null;
}
/**
* Opens a selection of {@link INewsMark} inside the feed view.
*
* @param page
* @param selection
*/
public static void openInFeedView(IWorkbenchPage page, IStructuredSelection selection) {
openInFeedView(page, selection, false);
}
/**
* Opens a selection of {@link INewsMark} inside the feed view.
*
* @param page
* @param selection
* @param forceActivate
*/
public static void openInFeedView(IWorkbenchPage page, IStructuredSelection selection, boolean forceActivate) {
openInFeedView(page, selection, forceActivate, false);
}
/**
* Opens a selection of {@link INewsMark} inside the feed view.
*
* @param page
* @param selection
* @param forceActivate
* @param ignoreAlreadyOpened
*/
public static void openInFeedView(IWorkbenchPage page, IStructuredSelection selection, boolean forceActivate, boolean ignoreAlreadyOpened) {
openInFeedView(page, selection, forceActivate, ignoreAlreadyOpened, null);
}
/**
* Opens a selection of {@link INewsMark} inside the feed view.
*
* @param page
* @param selection
* @param perform
* @param forceActivate
* @param ignoreAlreadyOpened
*/
public static void openInFeedView(IWorkbenchPage page, IStructuredSelection selection, boolean forceActivate, boolean ignoreAlreadyOpened, PerformAfterInputSet perform) {
try {
internalOpenInFeedView(page, selection, forceActivate, ignoreAlreadyOpened, false, perform);
} finally {
FeedView.setBlockFeedChangeEvent(false);
}
}
/**
* @param page
* @param selection
* @param openModes
*/
public static void openInFeedView(IWorkbenchPage page, IStructuredSelection selection, EnumSet<FeedViewOpenMode> openModes) {
boolean forceActivate = openModes.contains(FeedViewOpenMode.FORCE_ACTIVATE);
boolean ignoreAlreadyOpened = openModes.contains(FeedViewOpenMode.IGNORE_ALREADY_OPENED);
boolean ignoreReuse = openModes.contains(FeedViewOpenMode.IGNORE_REUSE);
try {
internalOpenInFeedView(page, selection, forceActivate, ignoreAlreadyOpened, ignoreReuse, null);
} finally {
FeedView.setBlockFeedChangeEvent(false);
}
}
private static void internalOpenInFeedView(IWorkbenchPage page, IStructuredSelection selection, boolean forceActivate, boolean ignoreAlreadyOpened, boolean ignoreReuse, PerformAfterInputSet perform) {
List<?> list = selection.toList();
boolean activateEditor = forceActivate || OpenStrategy.activateOnOpen();
int openedEditors = 0;
int maxOpenEditors = EditorUtils.getOpenEditorLimit();
boolean reuseFeedView = !ignoreReuse && Owl.getPreferenceService().getGlobalScope().getBoolean(DefaultPreferences.ALWAYS_REUSE_FEEDVIEW);
/* Open Editors for the given Selection */
for (int i = 0; i < list.size() && openedEditors < maxOpenEditors; i++) {
Object object = list.get(i);
/* Convert folder to news mark in case folder selected */
if (object instanceof IFolder)
object = new FolderNewsMark((IFolder) object);
/* Only news marks supported at this point */
if (object instanceof INewsMark) {
INewsMark mark = ((INewsMark) object);
FeedViewInput input = new FeedViewInput(mark, perform);
/* Start Blocking Feed Change Events if we open more than one Feed */
if (i == 1)
FeedView.setBlockFeedChangeEvent(true);
/* Open in existing Feedview if set */
if (reuseFeedView) {
/* Feed could be already open in editor (avoid duplicates) */
IEditorPart existingEditor = page.findEditor(input);
if (existingEditor != null) {
if (activateEditor)
page.activate(existingEditor);
else
page.bringToTop(existingEditor);
if (perform != null && existingEditor instanceof FeedView)
((FeedView) existingEditor).perform(perform);
break;
}
/* Otherwise replace the input in the first active feed view */
FeedView activeFeedView = OwlUI.getFirstActiveFeedView();
if (activeFeedView != null) {
activeFeedView.setInput(input);
if (activateEditor)
page.activate(activeFeedView);
else
page.bringToTop(activeFeedView);
break;
}
}
/* Otherwise simply open */
try {
boolean explicitPerform = false;
IEditorPart existingEditor = null;
if (perform != null) {
existingEditor = page.findEditor(input);
explicitPerform = (existingEditor != null);
}
/* Open Editor (check for already opened if set) */
if (!ignoreAlreadyOpened || page.findEditor(input) == null)
page.openEditor(input, FeedView.ID, activateEditor);
openedEditors++;
/* Pass in Perform Code */
if (explicitPerform && existingEditor instanceof FeedView)
((FeedView) existingEditor).perform(perform);
/* Break loop if we reuse feed views (thus can only display a single feed) */
if (reuseFeedView)
break;
} catch (PartInitException e) {
Activator.getDefault().getLog().log(e.getStatus());
}
}
}
}
/**
* Set's the checked state of all visible items to the suplied one.
*
* @param tree
* @param state
*/
public static void setAllChecked(Tree tree, boolean state) {
setAllChecked(state, tree.getItems());
}
private static void setAllChecked(boolean state, TreeItem[] items) {
for (int i = 0; i < items.length; i++) {
items[i].setChecked(state);
TreeItem[] children = items[i].getItems();
setAllChecked(state, children);
}
}
/** Identical with ActionFactory.CLOSE_OTHERS */
public static void closeOtherEditors() {
IWorkbenchPage page = getPage();
if (page != null) {
IEditorReference[] refArray = page.getEditorReferences();
if (refArray != null && refArray.length > 1) {
IEditorReference[] otherEditors = new IEditorReference[refArray.length - 1];
IEditorReference activeEditor = (IEditorReference) page.getReference(page.getActiveEditor());
for (int i = 0; i < refArray.length; i++) {
if (refArray[i] != activeEditor)
continue;
System.arraycopy(refArray, 0, otherEditors, 0, i);
System.arraycopy(refArray, i + 1, otherEditors, i, refArray.length - 1 - i);
break;
}
page.closeEditors(otherEditors, true);
}
}
}
/**
* @param text the {@link Text} to hook auto complete into.
* @param values the values that show up as proposal.
* @param decorate if <code>true</code>, decorate the control to indicate
* content assist is available.
* @param autoActivate
* @return Pair
*/
public static Pair<SimpleContentProposalProvider, ContentProposalAdapter> hookAutoComplete(final Text text, Collection<String> values, boolean decorate, boolean autoActivate) {
return hookAutoComplete(text, new ContentAssistAdapter(text, ' ', false), values, decorate, autoActivate);
}
/**
* @param combo the {@link Combo} to hook auto complete into.
* @param values the values that show up as proposal.
* @param decorate if <code>true</code>, decorate the control to indicate
* content assist is available.
* @return Pair
*/
public static Pair<SimpleContentProposalProvider, ContentProposalAdapter> hookAutoComplete(final Combo combo, Collection<String> values, boolean decorate) {
return hookAutoComplete(combo, new ContentAssistAdapter(combo, ' ', false), values, decorate, true);
}
/**
* @param control the {@link Control} to hook auto complete into.
* @param contentAdapter a {@link IControlContentAdapter} for the content
* @param values the values that show up as proposal.
* @param decorate if <code>true</code>, decorate the control to indicate
* content assist is available.
* @param autoActivate
* @return Pair
*/
public static Pair<SimpleContentProposalProvider, ContentProposalAdapter> hookAutoComplete(final Control control, IControlContentAdapter contentAdapter, Collection<String> values, boolean decorate, final boolean autoActivate) {
/* Show UI Hint that Content Assist is available */
if (decorate) {
ControlDecoration controlDeco = new ControlDecoration(control, SWT.LEFT | SWT.TOP);
controlDeco.setImage(FieldDecorationRegistry.getDefault().getFieldDecoration(FieldDecorationRegistry.DEC_CONTENT_PROPOSAL).getImage());
controlDeco.setDescriptionText(Messages.OwlUI_CONTENT_ASSIST);
controlDeco.setShowOnlyOnFocus(true);
}
/* Auto-Activate on Key-Down */
KeyStroke activationKey = KeyStroke.getInstance(SWT.ARROW_DOWN);
/* Create Content Proposal Adapter */
SimpleContentProposalProvider proposalProvider = new SimpleContentProposalProvider(new String[0]) {
@Override
public IContentProposal[] getProposals(String contents, int position) {
if (Display.getCurrent() != null && !control.isVisible())
return new IContentProposal[0];
return super.getProposals(contents, position);
}
};
proposalProvider.setFiltering(true);
final ContentProposalAdapter adapter = new ContentProposalAdapter(control, contentAdapter, proposalProvider, activationKey, null);
adapter.setPropagateKeys(true);
adapter.setAutoActivationDelay(1500);
adapter.setProposalAcceptanceStyle(ContentProposalAdapter.PROPOSAL_INSERT);
/* Apply Proposals */
if (values != null)
applyAutoCompleteProposals(values, proposalProvider, adapter, autoActivate);
/*
* TODO: This is a hack but there doesnt seem to be any API to set the size
* of the popup to match the actual size of the Text widget being used.
*/
control.getDisplay().timerExec(100, new Runnable() {
public void run() {
if (!control.isDisposed()) {
adapter.setPopupSize(new Point(control.getSize().x, 120));
}
}
});
return Pair.create(proposalProvider, adapter);
}
/**
* @param values
* @param provider
* @param adapter
* @param autoActivate
*/
public static void applyAutoCompleteProposals(Collection<String> values, SimpleContentProposalProvider provider, ContentProposalAdapter adapter, boolean autoActivate) {
/* Extract Proposals */
final String[] proposals = new String[values.size()];
Set<Character> charSet = new HashSet<Character>();
int i = 0;
for (String value : values) {
proposals[i] = value;
char c = value.charAt(0);
charSet.add(Character.toLowerCase(c));
charSet.add(Character.toUpperCase(c));
i++;
}
/* Auto-Activate on first Key typed */
char[] activationChars = new char[charSet.size()];
i = 0;
for (char c : charSet) {
activationChars[i] = c;
i++;
}
/* Apply proposals and auto-activation chars */
provider.setProposals(proposals);
if (autoActivate)
adapter.setAutoActivationCharacters(activationChars);
}
/**
* @param display
* @param rgb the color value to use in the image
* @return an {@link Image} for the color that must be disposed when no longer
* used.
*/
public static Image createColorImage(Display display, RGB rgb) {
Color color = new Color(display, rgb);
Image image = new Image(display, 12, 12);
GC gc = new GC(image);
gc.setBackground(color);
gc.fillRectangle(0, 0, 12, 12);
gc.setForeground(display.getSystemColor(SWT.COLOR_BLACK));
gc.drawRectangle(0, 0, 11, 11);
gc.dispose();
color.dispose();
return image;
}
/**
* @return the width for displaying a date.
*/
public static int getDateWidth() {
/* Check if Cached already */
if (DATE_WIDTH > 0)
return DATE_WIDTH;
/* Calculate and Cache */
DateFormat dF = getShortDateFormat();
Calendar cal = Calendar.getInstance();
cal.set(2006, Calendar.DECEMBER, 12, 12, 12, 12);
String sampleDate = dF.format(cal.getTime());
DATE_WIDTH = OwlUI.getTextSize(Display.getDefault(), OwlUI.getBold(HEADLINES_FONT_ID), sampleDate).x;
DATE_WIDTH += Application.IS_WINDOWS ? 15 : 30; // Bounds of Column requires more space
return DATE_WIDTH;
}
/**
* @return the width for displaying a state.
*/
public static int getStateWidth() {
/* Check if Cached already */
if (STATE_WIDTH > 0)
return STATE_WIDTH;
/* Calculate and Cache */
String sampleState = Messages.OwlUI_UPDATED;
STATE_WIDTH = OwlUI.getTextSize(Display.getDefault(), OwlUI.getBold(HEADLINES_FONT_ID), sampleState).x;
STATE_WIDTH += Application.IS_WINDOWS ? 25 : 30; // Bounds of Column requires more space (arrow indicator)
return STATE_WIDTH;
}
/**
* Custom Owner Drawn helper to draw a gradient across a Scrollable item.
*
* @param event the erase event.
* @param fg gradient foreground.
* @param bg gradient background.
* @param end gradient end.
*/
public static void codDrawGradient(Event event, Color fg, Color bg, Color end) {
Scrollable scrollable = (Scrollable) event.widget;
GC gc = event.gc;
Rectangle area = scrollable.getClientArea();
Rectangle rect = event.getBounds();
/* Paint the selection beyond the end of last column */
codExpandRegion(event, scrollable, gc, area);
/* Draw Gradient Rectangle */
Color oldForeground = gc.getForeground();
Color oldBackground = gc.getBackground();
/* Gradient */
gc.setForeground(fg);
gc.setBackground(bg);
gc.fillGradientRectangle(0, rect.y, area.width, rect.height, true);
/* Bottom Line */
gc.setForeground(end);
gc.drawLine(0, rect.y + rect.height - 1, area.width, rect.y + rect.height - 1);
gc.setForeground(oldForeground);
gc.setBackground(oldBackground);
/* Mark as Background being handled */
event.detail &= ~SWT.BACKGROUND;
}
/**
* Custom Owner Draw helper to expand a drawn region over a scrollable item.
*
* @param event the erase event.
* @param scrollable the scrollable to paint on.
* @param gc the gc to paint on.
* @param area the drawable area.
*/
public static void codExpandRegion(Event event, Scrollable scrollable, GC gc, Rectangle area) {
int columnCount;
if (scrollable instanceof Table)
columnCount = ((Table) scrollable).getColumnCount();
else
columnCount = ((Tree) scrollable).getColumnCount();
if (event.index == columnCount - 1 || columnCount == 0) {
int width = area.x + area.width - event.x;
if (width > 0) {
Region region = new Region();
gc.getClipping(region);
region.add(event.x, event.y, width, event.height);
gc.setClipping(region);
region.dispose();
}
}
}
/**
* @param shell the {@link Shell} as parent of the {@link WizardDialog}.
* @param wizard the {@link Wizard} to use in the {@link WizardDialog}.
* @param modal if <code>false</code>, the wizard will not be a modal dialog.
* @param needsProgressPart <code>true</code> to leave some room for the
* {@link ProgressMonitorPart} and <code>false</code> otherwise.
* @param dialogSettingsKey the key to use to store dialog settings.
*/
public static void openWizard(Shell shell, Wizard wizard, final boolean modal, final boolean needsProgressPart, final String dialogSettingsKey) {
openWizard(shell, wizard, modal, needsProgressPart, dialogSettingsKey, false, null);
}
/**
* @param shell the {@link Shell} as parent of the {@link WizardDialog}.
* @param wizard the {@link Wizard} to use in the {@link WizardDialog}.
* @param modal if <code>false</code>, the wizard will not be a modal dialog.
* @param needsProgressPart <code>true</code> to leave some room for the
* {@link ProgressMonitorPart} and <code>false</code> otherwise.
* @param dialogSettingsKey the key to use to store dialog settings.
* @param pack if <code>true</code>, make the wizard as compact as possible
* and <code>false</code> otherwise.
* @param finishLabel the label for the finish button or <code>null</code> to
* use the default.
*/
public static void openWizard(Shell shell, Wizard wizard, final boolean modal, final boolean needsProgressPart, final String dialogSettingsKey, final boolean pack, final String finishLabel) {
CustomWizardDialog dialog = new CustomWizardDialog(shell, wizard) {
private ProgressMonitorPart progressMonitorPart;
@Override
protected boolean isResizable() {
return true;
}
@Override
protected Control createDialogArea(Composite parent) {
Control control = super.createDialogArea(parent);
if (progressMonitorPart != null && !needsProgressPart)
((GridData) progressMonitorPart.getLayoutData()).exclude = true;
return control;
}
@Override
public boolean close() {
progressMonitorPart = null;
return super.close();
}
@Override
protected ProgressMonitorPart createProgressMonitorPart(Composite composite, GridLayout pmlayout) {
progressMonitorPart = super.createProgressMonitorPart(composite, pmlayout);
return progressMonitorPart;
}
@Override
protected IDialogSettings getDialogBoundsSettings() {
if (dialogSettingsKey != null) {
IDialogSettings settings = Activator.getDefault().getDialogSettings();
IDialogSettings section = settings.getSection(dialogSettingsKey);
if (section != null)
return section;
return settings.addNewSection(dialogSettingsKey);
}
return super.getDialogBoundsSettings();
}
@Override
protected int getShellStyle() {
if (modal)
return super.getShellStyle();
return SWT.TITLE | SWT.BORDER | SWT.MIN | SWT.RESIZE | SWT.CLOSE | getDefaultOrientation();
}
@Override
protected int getDialogBoundsStrategy() {
return DIALOG_PERSISTSIZE;
}
@Override
protected Button createButton(Composite parent, int id, String label, boolean defaultButton) {
if (IDialogConstants.FINISH_ID == id && StringUtils.isSet(finishLabel))
label = finishLabel;
return super.createButton(parent, id, label, defaultButton);
}
@Override
protected Point getInitialSize() {
if (pack) {
int width = Application.IS_WINDOWS ? WINDOWS_PACKED_WIZARD_WIDTH : Application.IS_LINUX ? LINUX_PACKED_WIZARD_WIDTH : MAC_PACKED_WIZARD_WIDTH;
return getShell().computeSize(convertHorizontalDLUsToPixels(width), SWT.DEFAULT, true);
}
return super.getInitialSize();
}
};
dialog.setMinimumPageSize(0, 0);
dialog.create();
dialog.open();
}
/**
* @param folder a selected {@link IFolder}
* @return the selected {@link IFolder} if part of the currently selected
* Bookmark Set, or the currently selected Bookmark Set otherwise.
* @throws PersistenceException in case of an error while loading.
*/
public static IFolder getSelectedParent(IFolder folder) throws PersistenceException {
String selectedBookMarkSetPref = BookMarkExplorer.getSelectedBookMarkSetPref(getWindow());
IPreference preference = DynamicDAO.getDAO(IPreferenceDAO.class).load(selectedBookMarkSetPref);
if (preference != null) {
Long selectedRootFolderID = preference.getLong();
/* Check if available Parent is still valid */
if (folder != null) {
if (hasParent(folder, new FolderReference(selectedRootFolderID)))
return folder;
}
/* Otherwise return visible root-folder */
return new FolderReference(selectedRootFolderID).resolve();
}
Set<IFolder> roots = CoreUtils.loadRootFolders();
if (!roots.isEmpty())
return roots.iterator().next();
return null;
}
private static boolean hasParent(IFolder folder, FolderReference folderRef) {
if (folder == null)
return false;
if (folderRef.references(folder))
return true;
return hasParent(folder.getParent(), folderRef);
}
/**
* Adjust the bounds of the given Shell to respect the addition or removal of
* the vertical bar.
*
* @param shell the Shell of the container.
* @param verticalBar the vertical {@link ScrollBar} of the container.
* @param wasScrollbarShowing <code>true</code> if the vertical scrollbar was
* showing and <code>false</code> otherwise.
*/
public static void adjustSizeForScrollbar(Shell shell, ScrollBar verticalBar, boolean wasScrollbarShowing) {
if (verticalBar == null)
return;
/* Ignore for application window */
if (shell.getParent() == null)
return;
int barWidth = verticalBar.getSize().x;
if (Application.IS_MAC && barWidth == 0)
barWidth = 16; //Can be 0 on Mac
if (wasScrollbarShowing != verticalBar.isVisible()) {
Rectangle shellBounds = shell.getBounds();
/* Increase if Scrollbar now Visible */
if (!wasScrollbarShowing)
shell.setBounds(shellBounds.x, shellBounds.y, shellBounds.width + barWidth, shellBounds.height);
/* Reduce if Scrollbar now Invisible */
else
shell.setBounds(shellBounds.x, shellBounds.y, shellBounds.width - barWidth, shellBounds.height);
}
}
/**
* @param name the name of the attachment.
* @param mimeType the mime type of the attachment or <code>null</code> if
* none.
* @return an {@link ImageDescriptor} for the attachment. Never
* <code>null</code>.
*/
public static ImageDescriptor getAttachmentImage(String name, String mimeType) {
/* First try to lookup image from Mime Type */
ImageDescriptor descriptor = getImageForMime(mimeType);
if (descriptor != null)
return descriptor;
/* Second try to lookup image from File Name */
descriptor = getImageForFile(name);
if (descriptor != null)
return descriptor;
/* Return Default */
return ATTACHMENT;
}
/* Find a Image for the given File Name using Program API from SWT */
private static ImageDescriptor getImageForFile(String file) {
if (StringUtils.isSet(file)) {
int lastIndexOfDot = file.lastIndexOf('.');
if (lastIndexOfDot != -1 && !file.endsWith(".")) { //$NON-NLS-1$
String extension = file.substring(lastIndexOfDot + 1);
return getImageForExtension(extension.toLowerCase());
}
}
return null;
}
/* Find a Image for the given Mime Type using Program API from SWT */
private static ImageDescriptor getImageForMime(String mime) {
if (StringUtils.isSet(mime)) {
String extension = getExtensionForMime(mime);
return getImageForExtension(extension);
}
return null;
}
/**
* @param mime the mime type
* @return the extension for the mime type or <code>null</code> if none
*/
public static String getExtensionForMime(String mime) {
if (StringUtils.isSet(mime))
return fgMapMimeToExtension.get(mime.toLowerCase());
return null;
}
/* Find a Image for the given Extension using Program API from SWT */
@SuppressWarnings("restriction")
private static ImageDescriptor getImageForExtension(String extension) {
if (StringUtils.isSet(extension)) {
Program p = Program.findProgram(extension);
if (p != null)
return new org.eclipse.ui.internal.misc.ExternalProgramImageDescriptor(p);
}
return null;
}
/**
* @param seconds the number of seconds.
* @return the period spanned by the seconds as human readable label.
*/
public static String getPeriod(int seconds) {
if (seconds > 0) {
int hours = seconds / 3600;
int minutes = (seconds / 60) % 60;
/* X Hours, Y Minutes */
if (hours > 0 && minutes > 0) {
if (hours == 1) {
if (minutes == 1)
return NLS.bind(Messages.OwlUI_HOUR_MINUTE, hours, minutes);
return NLS.bind(Messages.OwlUI_HOUR_MINUTES, hours, minutes);
}
if (minutes == 1)
return NLS.bind(Messages.OwlUI_HOURS_MINUTE, hours, minutes);
return NLS.bind(Messages.OwlUI_HOURS_MINUTES, hours, minutes);
}
/* X Hours */
else if (hours > 0)
return (hours == 1) ? NLS.bind(Messages.OwlUI_HOUR, hours) : NLS.bind(Messages.OwlUI_HOURS, hours);
/* X Minutes */
else if (hours == 0 && minutes > 0)
return (minutes == 1) ? NLS.bind(Messages.OwlUI_MINUTE, minutes) : NLS.bind(Messages.OwlUI_MINUTES, minutes);
/* X Seconds */
else if (seconds < 60)
return (seconds == 1) ? NLS.bind(Messages.OwlUI_SECOND, seconds) : NLS.bind(Messages.OwlUI_SECONDS, seconds);
}
return null;
}
/**
* @param bytes the number of bytes.
* @return a human readable representation of the bytes.
*/
public static String getSize(long bytes) {
if (bytes > 0) {
double gb = bytes / (1024d * 1024d * 1024d);
double mb = bytes / (1024d * 1024d);
double kb = bytes / 1024d;
NumberFormat format = new DecimalFormat(Messages.OwlUI_SIZE_FORMAT);
if (gb >= 1)
return NLS.bind(Messages.OwlUI_OwlUI_N_GB, format.format(gb));
if (mb >= 1)
return NLS.bind(Messages.OwlUI_N_MB, format.format(mb));
if (kb >= 1)
return NLS.bind(Messages.OwlUI_N_KB, format.format(kb));
return NLS.bind(Messages.OwlUI_N_BYTES, bytes);
}
return null;
}
/**
* @return the Size of the {@link Monitor} if only a single monitor is used or
* <code>null</code> if none.
*/
public static Point getFirstMonitorSize() {
Display display = Display.getDefault();
if (display != null) {
Monitor[] monitors = display.getMonitors();
if (monitors.length == 1) {
Rectangle clientArea = monitors[0].getClientArea();
return new Point(clientArea.width, clientArea.height);
}
}
return null;
}
/**
* Switch between full-screen and normal screen.
*/
public static void toggleFullScreen() {
Shell shell = OwlUI.getActiveShell();
if (shell != null) {
shell.setFullScreen(!shell.getFullScreen());
/* Shell got restored */
if (!shell.getFullScreen()) {
ApplicationWorkbenchWindowAdvisor configurer = ApplicationWorkbenchAdvisor.fgPrimaryApplicationWorkbenchWindowAdvisor;
configurer.setStatusVisible(Owl.getPreferenceService().getGlobalScope().getBoolean(DefaultPreferences.SHOW_STATUS), false);
shell.layout(); //Need to layout to avoid screen cheese
}
/* Shell got fullscreen */
else {
ApplicationWorkbenchWindowAdvisor configurer = ApplicationWorkbenchAdvisor.fgPrimaryApplicationWorkbenchWindowAdvisor;
configurer.setStatusVisible(false, true);
}
}
}
/**
* Switch between showing and hiding the Bookmarks View.
*/
public static void toggleBookmarks() {
IWorkbenchPage page = OwlUI.getPage();
if (page != null) {
IViewPart explorerView = page.findView(BookMarkExplorer.VIEW_ID);
/* Hide Bookmarks */
if (explorerView != null)
page.hideView(explorerView);
/* Show Bookmarks */
else {
try {
page.showView(BookMarkExplorer.VIEW_ID);
} catch (PartInitException e) {
Activator.getDefault().logError(e.getMessage(), e);
}
}
}
}
/**
* @param action the dropdown action.
* @param manager the toolbar containing the action.
*/
public static void positionDropDownMenu(Action action, ToolBarManager manager) {
Menu menu = action.getMenuCreator().getMenu(manager.getControl());
if (menu != null) {
/* Adjust Location */
IContributionItem contributionItem = manager.find(action.getId());
if (contributionItem != null && contributionItem instanceof ActionContributionItem) {
Widget widget = ((ActionContributionItem) contributionItem).getWidget();
if (widget != null && widget instanceof ToolItem) {
ToolItem item = (ToolItem) widget;
Rectangle rect = item.getBounds();
Point pt = new Point(rect.x, rect.y + rect.height);
pt = manager.getControl().toDisplay(pt);
if (Application.IS_MAC)
pt.y += 5;
menu.setLocation(pt.x, pt.y);
}
}
/* Set Visible */
menu.setVisible(true);
}
}
/**
* @param zoomIn
* @param reset
*/
@SuppressWarnings("restriction")
public static void zoomNewsText(boolean zoomIn, boolean reset) {
/* Retrieve Font */
ITheme theme = PlatformUI.getWorkbench().getThemeManager().getCurrentTheme();
FontRegistry registry = theme.getFontRegistry();
FontData[] oldFontDatas = registry.getFontData(NEWS_TEXT_FONT_ID);
FontData[] newFontDatas = new FontData[oldFontDatas.length];
/* Set Height */
for (int i = 0; i < oldFontDatas.length; i++) {
FontData oldFontData = oldFontDatas[i];
int oldHeight = oldFontData.getHeight();
if (reset)
newFontDatas[i] = new FontData(oldFontData.getName(), DEFAULT_NEWS_TEXT_FONT_HEIGHT, oldFontData.getStyle());
else
newFontDatas[i] = new FontData(oldFontData.getName(), zoomIn ? oldHeight + 1 : Math.max(oldHeight - 1, 0), oldFontData.getStyle());
}
registry.put(NEWS_TEXT_FONT_ID, newFontDatas);
/* Store in Preferences */
String key = org.eclipse.ui.internal.themes.ThemeElementHelper.createPreferenceKey(theme, NEWS_TEXT_FONT_ID);
String fdString = PreferenceConverter.getStoredRepresentation(newFontDatas);
String storeString = org.eclipse.ui.internal.util.PrefUtil.getInternalPreferenceStore().getString(key);
if (!fdString.equals(storeString))
org.eclipse.ui.internal.util.PrefUtil.getInternalPreferenceStore().setValue(key, fdString);
}
/**
* @param run the {@link Runnable} to run on selection changes.
* @param control the control to add selection listener to. Will recursively
* go into child controls for Composites.
*/
public static void runOnSelection(final Runnable run, Control... control) {
for (Control c : control) {
/* Button */
if (c instanceof Button) {
Button button = (Button) c;
button.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
run.run();
}
});
}
/* Combo */
else if (c instanceof Combo) {
Combo combo = (Combo) c;
combo.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
run.run();
}
});
}
/* Tree */
else if (c instanceof Tree) {
Tree tree = (Tree) c;
tree.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
if ((e.detail & SWT.CHECK) != 0)
run.run();
}
});
tree.addDragDetectListener(new DragDetectListener() {
public void dragDetected(DragDetectEvent e) {
run.run();
}
});
}
/* Table */
else if (c instanceof Table) {
Table table = (Table) c;
table.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
if ((e.detail & SWT.CHECK) != 0)
run.run();
}
});
table.addDragDetectListener(new DragDetectListener() {
public void dragDetected(DragDetectEvent e) {
run.run();
}
});
}
/* Spinner */
else if (c instanceof Spinner) {
Spinner spinner = (Spinner) c;
spinner.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
run.run();
}
});
}
/* Text */
else if (c instanceof Text) {
Text text = (Text) c;
text.addModifyListener(new ModifyListener() {
public void modifyText(ModifyEvent e) {
run.run();
}
});
}
/* Composite */
else if (c instanceof Composite) {
Composite composite = (Composite) c;
runOnSelection(run, composite.getChildren());
}
}
}
/**
* @return the {@link DateFormat} used for short dates. Respects the system
* property to override this value from default.
*/
public static DateFormat getShortDateFormat() {
String format = System.getProperty(SHORT_DATE_FORMAT_PROPERTY);
if (StringUtils.isSet(format)) {
try {
return new SimpleDateFormat(format);
} catch (Exception e) {
/* Ignore and use Default */
}
}
return DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT);
}
/**
* @return the {@link DateFormat} used for long dates. Respects the system
* property to override this value from default.
*/
public static DateFormat getLongDateFormat() {
String format = System.getProperty(LONG_DATE_FORMAT_PROPERTY);
if (StringUtils.isSet(format)) {
try {
return new SimpleDateFormat(format);
} catch (Exception e) {
/* Ignore and use Default */
}
}
return DateFormat.getDateTimeInstance(DateFormat.FULL, DateFormat.SHORT);
}
/**
* @return the {@link DateFormat} used for short times. Respects the system
* property to override this value from default.
*/
public static DateFormat getShortTimeFormat() {
String format = System.getProperty(SHORT_TIME_FORMAT_PROPERTY);
if (StringUtils.isSet(format)) {
try {
return new SimpleDateFormat(format);
} catch (Exception e) {
/* Ignore and use Default */
}
}
return DateFormat.getTimeInstance(DateFormat.SHORT);
}
/**
* @param control the control to provide an accessible name for.
* @param label the label control to take the label from.
*/
public static void makeAccessible(Control control, Control label) {
if (label == null || label.isDisposed())
return;
if (label instanceof Button)
makeAccessible(control, ((Button) label).getText());
else if (label instanceof Label)
makeAccessible(control, ((Label) label).getText());
else if (label instanceof CLabel)
makeAccessible(control, ((CLabel) label).getText());
}
/**
* @param control the control to provide an accessible name for.
* @param name the name for the control to be used in accessible environments.
*/
public static void makeAccessible(final Control control, String name) {
/* Strip Mnemonics */
final String accessibleName;
if (name.contains("&")) //$NON-NLS-1$
accessibleName = StringUtils.replaceAll(name, "&", ""); //$NON-NLS-1$ //$NON-NLS-2$
else
accessibleName = name;
/* Apply Accessible Name */
if (control != null && !control.isDisposed()) {
control.getAccessible().addAccessibleListener(new AccessibleAdapter() {
@Override
public void getName(AccessibleEvent e) {
if (control instanceof Tree || control instanceof Table) {
if (e.childID == ACC.CHILDID_SELF)
e.result = accessibleName;
else if (!control.isDisposed()) {
Widget widget = control.getDisplay().findWidget(control, e.childID);
if (widget != null && widget instanceof Item)
e.result = NLS.bind(Messages.OwlUI_ACCESSIBLE_NAME, ((Item) widget).getText());
}
} else
e.result = accessibleName;
}
});
}
}
/**
* @return <code>true</code> if tabbed browsing is enabled and
* <code>false</code> otherwise.
*/
public static boolean isTabbedBrowsingEnabled() {
IPreferenceScope preferences = Owl.getPreferenceService().getEclipseScope();
boolean autoCloseTabs = preferences.getBoolean(DefaultPreferences.ECLIPSE_AUTOCLOSE_TABS);
int autoCloseTabsThreshold = preferences.getInteger(DefaultPreferences.ECLIPSE_AUTOCLOSE_TABS_THRESHOLD);
return !autoCloseTabs || autoCloseTabsThreshold > 1;
}
/**
* @return <code>true</code> if RSSOwl is minimized (either its Shell or
* minimized to tray) and <code>false</code> otherwise.
*/
public static boolean isMinimized() {
ApplicationWorkbenchWindowAdvisor advisor = ApplicationWorkbenchAdvisor.fgPrimaryApplicationWorkbenchWindowAdvisor;
if (advisor != null && (advisor.isMinimizedToTray() || advisor.isMinimized()))
return true;
return false;
}
/**
* @return <code>true</code> if the user has configured to use an external
* browser and <code>false</code> otherwise.
*/
public static boolean useExternalBrowser() {
IPreferenceScope preferences = Owl.getPreferenceService().getGlobalScope();
return preferences.getBoolean(DefaultPreferences.USE_DEFAULT_EXTERNAL_BROWSER) || preferences.getBoolean(DefaultPreferences.USE_CUSTOM_EXTERNAL_BROWSER);
}
/**
* @return the currently selected {@link IFolder} as bookmark set from the
* feeds view or the first root folder otherwise. Falls back to
* <code>null</code> if neither can be resolved.
*/
public static IFolder getSelectedBookMarkSet() {
IPreferenceScope preferences = Owl.getPreferenceService().getGlobalScope();
IFolderDAO folderDAO = DynamicDAO.getDAO(IFolderDAO.class);
String selectedBookMarkSetPref = BookMarkExplorer.getSelectedBookMarkSetPref(getWindow());
long selectedFolderID = preferences.getLong(selectedBookMarkSetPref);
IFolder selectedSet = folderDAO.load(selectedFolderID);
if (selectedSet != null)
return selectedSet;
Set<IFolder> rootFolders = CoreUtils.loadRootFolders();
if (!rootFolders.isEmpty())
return rootFolders.iterator().next();
return null;
}
/**
* @return <code>true</code> if the preference tell to update duplicate news
* states when marking as read and <code>false</code> otherwise.
*/
public static boolean markReadDuplicates() {
IPreferenceScope preferences = Owl.getPreferenceService().getGlobalScope();
return preferences.getBoolean(DefaultPreferences.MARK_READ_DUPLICATES);
}
/**
* @param scope the preferences scope to look for the defined layout.
* @return the selected {@link Layout} from the given preferences scope.
*/
public static Layout getLayout(IPreferenceScope scope) {
int layoutOrdinal = scope.getInteger(DefaultPreferences.FV_LAYOUT);
Layout[] layouts = Layout.values();
return layoutOrdinal < layouts.length ? layouts[layoutOrdinal] : Layout.CLASSIC;
}
/**
* @param scope the preferences scope to look for the defined page size.
* @return the selected {@link PageSize} from the given preferences scope.
*/
public static PageSize getPageSize(IPreferenceScope scope) {
int pageSize = scope.getInteger(DefaultPreferences.NEWS_BROWSER_PAGE_SIZE);
return PageSize.from(pageSize);
}
/**
* Safely disposes the provided {@link Menu}.
*
* @param menu the {@link Menu} to dispose.
*/
public static void safeDispose(Menu menu) {
try {
menu.dispose();
} catch (NegativeArraySizeException e) {
/* Bug in SWT that we can safely ignore */
}
}
/**
* Opens a file dialog to save the crash report.
*
* @param shell the parent {@link Shell} of the dialog that opens.
* @throws FileNotFoundException in case of an error
*/
public static void saveCrashReport(Shell shell) throws FileNotFoundException {
FileDialog dialog = new FileDialog(shell, SWT.SAVE);
dialog.setText(Messages.OwlUI_SAVE_CRASH_REPORT);
dialog.setFilterExtensions(new String[] { "*.log" }); //$NON-NLS-1$
dialog.setFileName("rssowl.log"); //$NON-NLS-1$
dialog.setOverwrite(true);
String file = dialog.open();
if (StringUtils.isSet(file)) {
/* Check for Log Message from Core to have a complete log */
String logMessages = CoreUtils.getAndFlushLogMessages();
if (logMessages != null && logMessages.length() > 0)
Activator.safeLogError(logMessages, null);
/* Help to find out where the log is coming from */
Activator.safeLogInfo("Crash Report Exported"); //$NON-NLS-1$
/* Export Log File */
File logFile = Platform.getLogFileLocation().toFile();
InputStream inS;
if (logFile.exists())
inS = new FileInputStream(logFile);
else
inS = new ByteArrayInputStream(new byte[0]);
FileOutputStream outS = new FileOutputStream(new File(file));
CoreUtils.copy(inS, outS);
}
}
/**
* Opens the Login Dialog to authenticate against sync services.
*
* @param shell the {@link Shell} as parent of the dialog or <code>null</code>
* if none.
* @return one of the {@link IDialogConstants} depending on the users choice
* of closing the dialog with OK or Cancel.
*/
public static int openSyncLogin(Shell shell) {
if (shell == null)
shell = getActiveShell();
if (shell != null) {
URI googleLoginUri = URI.create(SyncUtils.GOOGLE_LOGIN_URL);
LoginDialog dialog = new LoginDialog(shell, googleLoginUri, null, true);
dialog.setHeader(Messages.OwlUI_SYNC_LOGIN);
dialog.setSubline(Messages.OwlUI_SYNC_LOGIN_TEXT);
dialog.setTitleImageDescriptor(OwlUI.getImageDescriptor("icons/wizban/reader_wiz.png")); //$NON-NLS-1$
return dialog.open();
}
return IDialogConstants.CANCEL_ID;
}
/**
* @return <code>true</code> in case the a text control needs an extra cancel
* control to clear a search and <code>false</code> if the OS provides a
* native one already.
*/
public static boolean needsCancelControl() {
if (Application.IS_WINDOWS)
return true; //Windows does not support a native cancel button in text fields
if (Application.IS_MAC)
return false; //Mac supports native cancel button in text fields
return SWT.getVersion() < 3700; //Some Linux distros support it with recent SWT version
}
}