package com.aptana.ide.intro.actions; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; import java.net.URLConnection; import org.eclipse.core.runtime.IPath; import org.eclipse.jface.action.ActionContributionItem; import org.eclipse.jface.action.CoolBarManager; import org.eclipse.jface.action.IAction; import org.eclipse.jface.action.IContributionItem; import org.eclipse.jface.internal.provisional.action.IToolBarContributionItem; import org.eclipse.jface.preference.IPreferenceStore; import org.eclipse.jface.viewers.ISelection; import org.eclipse.swt.SWT; import org.eclipse.swt.SWTException; 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.widgets.Control; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Menu; import org.eclipse.swt.widgets.ToolItem; import org.eclipse.ui.IEditorPart; import org.eclipse.ui.IWorkbenchWindow; import org.eclipse.ui.IWorkbenchWindowPulldownDelegate2; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.internal.WWinPluginPulldown; import org.eclipse.ui.internal.WorkbenchWindow; import com.aptana.ide.core.IdeLog; import com.aptana.ide.core.online.OnlineDetectionService; import com.aptana.ide.core.ui.CoreUIUtils; import com.aptana.ide.core.ui.PerspectiveManager; import com.aptana.ide.core.ui.WebPerspectiveFactory; import com.aptana.ide.intro.IntroPlugin; import com.aptana.ide.intro.preferences.IPreferenceConstants; /** * Show the "My Aptana" actions drop-down in the toolbar. * * @author Shalom Gibly */ @SuppressWarnings("restriction") public class ShowMyAptanaAction implements IWorkbenchWindowPulldownDelegate2 { private static final String CACHED_IMAGE = "cached_intro_image"; //$NON-NLS-1$ private static final String LOCAL_IMAGE_LOCATION = "/icons/aptana_home.png"; //$NON-NLS-1$ private static final int DAY = 1000 * 60 * 60 * 24; private IWorkbenchWindow window; private Menu toolbarMenu = null; private ToolItem toolItem; private ImageLoader loader; private ImageData[] imageData; private Thread animateThread; private Image[] image; private long lastChecked; private boolean animationRunning; public ShowMyAptanaAction() { } /** * org.eclipse.ui.IWorkbenchWindowPulldownDelegate#getMenu(org.eclipse.swt. widgets.Control) */ public Menu getMenu(Control parent) { if (toolbarMenu != null) { toolbarMenu.dispose(); } toolbarMenu = new Menu(parent); buildMenu(toolbarMenu); return toolbarMenu; } /** * @see org.eclipse.ui.IWorkbenchWindowPulldownDelegate2#getMenu(org.eclipse.swt.widgets.Menu) */ public Menu getMenu(Menu parent) { Menu menu = new Menu(parent); buildMenu(menu); return menu; } /** * @see org.eclipse.ui.IWorkbenchWindowActionDelegate#dispose() */ public void dispose() { if (toolbarMenu != null) { toolbarMenu.dispose(); toolbarMenu = null; } toolItem = null; animateThread = null; if (image != null) { for (int i = 0; i < image.length; i++) { image[i].dispose(); } } } /** * @see org.eclipse.ui.IWorkbenchWindowActionDelegate#init(org.eclipse.ui.IWorkbenchWindow) */ public void init(IWorkbenchWindow window) { this.window = window; } /** * @see org.eclipse.ui.IActionDelegate#run(org.eclipse.jface.action.IAction) */ public void run(IAction action) { if (animationRunning) { // stops the animation animationRunning = false; } openEditor(); } /** * @see org.eclipse.ui.IActionDelegate#selectionChanged(org.eclipse.jface.action.IAction, * org.eclipse.jface.viewers.ISelection) */ public void selectionChanged(IAction action, ISelection selection) { // locates the ToolItem associated with the action if (action == null || !(action instanceof WWinPluginPulldown)) { return; } if (toolItem == null) { CoolBarManager manager = ((WorkbenchWindow) this.window).getCoolBarManager(); // this returns the list of actionSets groups IContributionItem[] items = manager.getItems(); for (IContributionItem item : items) { if (item instanceof IToolBarContributionItem) { IToolBarContributionItem toolbarItem = (IToolBarContributionItem) item; // this returns the list of actual items for the actions IContributionItem[] children = toolbarItem.getToolBarManager().getItems(); String id; for (IContributionItem child : children) { id = child.getId(); if (id != null && id.equals(action.getId())) { // found the toolbar item that corresponds to the // action ActionContributionItem actionItem = (ActionContributionItem) child; toolItem = (ToolItem) actionItem.getWidget(); if (toolItem != null) { File file = getLocalImageFile(); if (file.exists()) { setDefaultImage(file.getPath()); } else { setDefaultImage(IntroPlugin.getDefault().getPreferenceStore().getString( IPreferenceConstants.INTRO_TOOLBAR_DEFAULT_IMAGE)); } break; } } } } } } if (toolItem == null || !haventCheckedInADay()) { return; } lastChecked = System.currentTimeMillis(); if (!isRemoteImageUpdated()) { return; } loadImage(); toolItem.setImage(image[0]); updateCoolbar(); if (isAnimated()) { startAnimationThreads(toolItem); } } public static void openEditor() { switchPerspective(); IPreferenceStore prefs = IntroPlugin.getDefault().getPreferenceStore(); String editorId = prefs.getString(IPreferenceConstants.INTRO_EDITOR_ID); IEditorPart editorPart = CoreUIUtils.openEditor(editorId, true); if (editorPart == null) { // falls back to the default editorId = prefs.getDefaultString(IPreferenceConstants.INTRO_EDITOR_ID); prefs.setValue(IPreferenceConstants.INTRO_EDITOR_ID, editorId); CoreUIUtils.openEditor(editorId, true); } } private void buildMenu(Menu menu) { ActionUtils.buildMenu(menu, window); } /* * In case needed (and approved by the user), we will switch to the Aptana perspective. */ private static void switchPerspective() { IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow(); if (PerspectiveManager.shouldSwitchPerspective(window, WebPerspectiveFactory.PERSPECTIVE_ID)) { PerspectiveManager.switchToPerspective(window, WebPerspectiveFactory.PERSPECTIVE_ID); } } private void setDefaultImage(String filepath) { if (filepath == null || filepath.length() == 0) { return; } loader = new ImageLoader(); try { imageData = loader.load(filepath); if (imageData.length > 0) { image = new Image[1]; image[0] = new Image(Display.getCurrent(), imageData[0]); toolItem.setImage(image[0]); updateCoolbar(); } } catch (Exception e) { IdeLog.logImportant(IntroPlugin.getDefault(), e.getLocalizedMessage(), e); } } private void loadImage() { loader = new ImageLoader(); boolean loaded = false; InputStream stream = getRemoteImageStream(); if (stream != null) { try { imageData = loader.load(stream); loaded = true; cacheImage(); } catch (SWTException e) { } } if (!loaded) { // failed to get the remote image; falls back to the cached one imageData = loader.load(getLocalImageStream()); } int numFramesOfAnimation = imageData.length; image = new Image[numFramesOfAnimation]; int fullWidth = loader.logicalScreenWidth; int fullHeight = loader.logicalScreenHeight; Display display = Display.getCurrent(); for (int i = 0; i < numFramesOfAnimation; ++i) { if (i == 0) { // for the first frame of animation, just draw the first frame image[i] = new Image(display, imageData[i]); fullWidth = imageData[i].width; fullHeight = imageData[i].height; } else { // after the first frame of animation, draw the background // or previous frame first, then the new image data image[i] = new Image(display, fullWidth, fullHeight); GC gc = new GC(image[i]); gc.fillRectangle(0, 0, fullWidth, fullHeight); switch (imageData[i].disposalMethod) { case SWT.DM_FILL_BACKGROUND: gc.fillRectangle(imageData[i].x, imageData[i].y, imageData[i].width, imageData[i].height); break; default: /* Restore the previous image before drawing. */ gc.drawImage(image[i - 1], 0, 0, fullWidth, fullHeight, 0, 0, fullWidth, fullHeight); break; } Image newFrame = new Image(display, imageData[i]); gc.drawImage(newFrame, 0, 0, imageData[i].width, imageData[i].height, imageData[i].x, imageData[i].y, imageData[i].width, imageData[i].height); newFrame.dispose(); gc.dispose(); } } } private void startAnimationThreads(final ToolItem item) { animationRunning = true; animateThread = new Thread("Intro icon animation") { //$NON-NLS-1$ private int imageDataIndex = 0; public void run() { Display display = Display.getDefault(); try { int repeatCount = loader.repeatCount; while (animationRunning && (loader.repeatCount == 0 || repeatCount > 0)) { imageDataIndex = (imageDataIndex + 1) % imageData.length; if (!display.isDisposed()) { display.asyncExec(new Runnable() { public void run() { if (!item.isDisposed()) { item.setImage(image[imageDataIndex]); } } }); } // Sleep for the specified delay time (adding // commonly-used slow-down fudge factors). try { int ms = imageData[imageDataIndex].delayTime * 10; if (ms < 20) { ms += 30; } if (ms < 30) { ms += 10; } Thread.sleep(ms); } catch (InterruptedException e) { } // If we have just drawn the last image, decrement the // repeat count and start again. if (imageDataIndex == imageData.length - 1) { repeatCount--; } } } catch (SWTException e) { IdeLog.logError(IntroPlugin.getDefault(), e.getLocalizedMessage(), e); } } }; animateThread.setDaemon(true); animateThread.start(); } private boolean isAnimated() { return imageData.length > 1; } /** * @return true if there is a new remote image for the action */ private boolean isRemoteImageUpdated() { HttpURLConnection httpURLConnection = null; try { URL location = new URL(getRemoteImageLocation()); URLConnection urlConnection = location.openConnection(); if (urlConnection instanceof HttpURLConnection) { httpURLConnection = (HttpURLConnection) urlConnection; httpURLConnection.setConnectTimeout(1000); httpURLConnection.setUseCaches(false); httpURLConnection.addRequestProperty("Cache-Control", "no-cache"); //$NON-NLS-1$ //$NON-NLS-2$ httpURLConnection.setRequestMethod("HEAD"); //$NON-NLS-1$ if (httpURLConnection.getResponseCode() == HttpURLConnection.HTTP_OK) { // Check for lastModified? boolean updated = true; IPreferenceStore pref = IntroPlugin.getDefault().getPreferenceStore(); long lastModified = httpURLConnection.getLastModified(); if (lastModified == 0) { // unknown } else { long lastLastModified = pref.getLong(location.toString()); if (lastLastModified >= lastModified) { updated = false; } } pref.setValue(location.toString(), lastModified); return updated; } } } catch (MalformedURLException e) { } catch (IOException e) { } finally { // cleanup if (httpURLConnection != null) { httpURLConnection.disconnect(); } } return false; } private InputStream getLocalImageStream() { File file = getLocalImageFile(); if (file.exists()) { try { return file.toURI().toURL().openStream(); } catch (MalformedURLException e) { } catch (IOException e) { } } // no cached version; uses the local one in the plugin return getClass().getResourceAsStream(LOCAL_IMAGE_LOCATION); } private InputStream getRemoteImageStream() { String remoteLocation = getRemoteImageLocation(); try { URL url = new URL(remoteLocation); if (OnlineDetectionService.isAvailable(url)) { return url.openStream(); } } catch (MalformedURLException e) { } catch (IOException e) { } return null; } private File getLocalImageFile() { IPath directory = IntroPlugin.getDefault().getStateLocation(); String remotePath = getRemoteImageLocation(); String ext = getExtension(remotePath); return directory.append(CACHED_IMAGE + ext).toFile(); } private void cacheImage() { String filepath = getLocalImageFile().getAbsolutePath(); loader.save(filepath, getImageFormat(getExtension(filepath))); } private boolean haventCheckedInADay() { return lastChecked == 0 || lastChecked < System.currentTimeMillis() - DAY; } private void updateCoolbar() { // resizes the coolbar appropriately ((WorkbenchWindow) this.window).getCoolBarManager().update(true); } private static String getRemoteImageLocation() { return IntroPlugin.getDefault().getPreferenceStore().getString( IPreferenceConstants.INTRO_TOOLBAR_IMAGE_LOCATION); } private static String getExtension(String filepath) { int index = filepath.lastIndexOf("."); //$NON-NLS-1$ return index < 0 ? "" : filepath.substring(index); //$NON-NLS-1$ } private static int getImageFormat(String extension) { if (extension.equals(".png")) { //$NON-NLS-1$ return SWT.IMAGE_PNG; } if (extension.equals(".gif")) { //$NON-NLS-1$ return SWT.IMAGE_GIF; } if (extension.equals(".bmp")) { //$NON-NLS-1$ return SWT.IMAGE_BMP; } if (extension.equals(".jpg")) { //$NON-NLS-1$ return SWT.IMAGE_JPEG; } return SWT.IMAGE_ICO; } }