/*******************************************************************************
* Copyright (c) 2012, 2015 Wind River Systems, Inc. and others. 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.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Wind River Systems - initial API and implementation
*******************************************************************************/
package org.eclipse.tcf.te.tcf.filesystem.ui.internal.columns;
import java.awt.Component;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.beans.PropertyChangeEvent;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import javax.imageio.ImageIO;
import javax.swing.Icon;
import javax.swing.JComponent;
import javax.swing.filechooser.FileSystemView;
import org.eclipse.core.runtime.ISafeRunnable;
import org.eclipse.core.runtime.SafeRunner;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.swt.graphics.Image;
import org.eclipse.tcf.te.core.interfaces.IPropertyChangeProvider;
import org.eclipse.tcf.te.tcf.filesystem.core.interfaces.runtime.IFSTreeNode;
import org.eclipse.tcf.te.tcf.filesystem.core.model.ModelManager;
import org.eclipse.tcf.te.tcf.filesystem.ui.activator.UIPlugin;
import org.eclipse.tcf.te.tcf.filesystem.ui.internal.ImageConsts;
/**
* The background daemon that updates the images of the file system using
* images retrieved by FileSystemView from Swing.
*/
public class LabelProviderUpdateDaemon extends Thread {
private static String[][] os_drives = {
{"windows xp", "xp_rootdrive.png"}, //$NON-NLS-1$ //$NON-NLS-2$
{"windows 7", "win7_rootdrive.png"}, //$NON-NLS-1$//$NON-NLS-2$
{"windows 8", "win8_rootdrive.png"} //$NON-NLS-1$//$NON-NLS-2$
};
private static String root_drive = createRootImage(getOSEntry());
private static int getOSEntry() {
String osName = System.getProperty("os.name").toLowerCase(); //$NON-NLS-1$
for(int i = 0; i < os_drives.length;i++) {
if(os_drives[i][0].equals(osName)) return i;
}
return 0;
}
private static String createRootImage(int i) {
UIPlugin plugin = UIPlugin.getDefault();
URL url = plugin.getBundle().getEntry(ImageConsts.IMAGE_DIR_ROOT + ImageConsts.IMAGE_DIR_OBJ + os_drives[i][1]);
plugin.getImageRegistry().put(os_drives[i][0], ImageDescriptor.createFromURL(url));
return os_drives[i][0];
}
// The dummy AWT component used to render the icon.
Component dummyComponent = new JComponent(){private static final long serialVersionUID = 5926798769323111209L;};
//The queue that caches the current file nodes to be updated.
BlockingQueue<IFSTreeNode> queueNodes;
// The image update adapter for a file which has a local cache copy.
ImageUpdateAdapter cacheAdapter;
// The image update adapter for a file which does not has a local cache copy.
ImageUpdateAdapter extAdapter;
/**
* Constructor
*/
public LabelProviderUpdateDaemon() {
super("Image Updater Daemon"); //$NON-NLS-1$
setDaemon(true);
this.queueNodes = new LinkedBlockingQueue<IFSTreeNode>();
this.cacheAdapter = new CacheFileImageUpdater();
this.extAdapter = new FileExtBasedImageUpdater(this);
}
/**
* Cache the node which is to be updated with its icon in the file tree.
*
* @param node The node to be enqueued
*/
public void enqueue(final IFSTreeNode node) {
SafeRunner.run(new ISafeRunnable() {
@Override
public void handleException(Throwable exception) {
// Ignore
}
@Override
public void run() throws Exception {
queueNodes.put(node);
}
});
}
/**
* Take next node to be processed.
*
* @return The next node.
*/
private IFSTreeNode take() {
while (true) {
try {
return queueNodes.take();
}
catch (InterruptedException e) {
}
}
}
/*
* (non-Javadoc)
* @see java.lang.Thread#run()
*/
@Override
public void run() {
while (true) {
IFSTreeNode node = take();
ImageUpdateAdapter adapter = getUpdateAdapter(node);
String imgKey = adapter.getImageKey(node);
ImageDescriptor image = UIPlugin.getImageDescriptor(imgKey);
if (image == null) {
File mrrFile = adapter.getMirrorFile(node);
File imgFile = adapter.getImageFile(node);
image = createImage(imgKey, mrrFile, imgFile);
}
if (image != null) {
sendNotification(node, node.getName(), null, image);
}
}
}
/**
* Select an image update adapter for the specified node.
*
* @param node The IFSTreeNode.
* @return an image update adapter, either cache based or extension based.
*/
private ImageUpdateAdapter getUpdateAdapter(IFSTreeNode node) {
File cacheFile = node.getCacheFile();
if (cacheFile.exists()) {
return cacheAdapter;
}
return extAdapter;
}
/**
* Get the image for the specified node from its
* image update adapter.
*
* @param node The file system tree node.
* @return The image or null if there's no image yet.
*/
public Image getImage(IFSTreeNode node) {
ImageUpdateAdapter adapter = getUpdateAdapter(node);
String key = adapter.getImageKey(node);
return UIPlugin.getImage(key);
}
/**
* Create an Image Descriptor based on the mirror file and store
* it in the imgFile and store it using the specified image key.
*
* @param imgKey The image key.
* @param mrrFile The mirror file used to create the image.
* @param imgFile The image file used to store the image data.
* @return The Image Descriptor describing the image or null if it is not successful.
*/
private ImageDescriptor createImage(String imgKey, File mrrFile, File imgFile) {
ImageDescriptor image = UIPlugin.getImageDescriptor(imgKey);
if (image == null) {
if (!imgFile.exists()) {
FileSystemView view = FileSystemView.getFileSystemView();
Icon icon = view.getSystemIcon(mrrFile);
if (icon != null) createImageFromIcon(icon, imgFile);
}
if (imgFile.exists()) {
try {
image = ImageDescriptor.createFromURL(imgFile.toURI().toURL());
UIPlugin.getDefault().getImageRegistry().put(imgKey, image);
}
catch (MalformedURLException e) {
// Ignore
}
}
}
return image;
}
/**
* Get the image of disk drivers on Windows platform.
*
* @return The disk driver image.
*/
public Image getDiskImage() {
return UIPlugin.getImage(root_drive);
}
/**
* Get the folder image on Windows platform.
*
* @return The folder image.
*/
public Image getFolderImage() {
String key = "SWING_FOLDER_IMAGE"; //$NON-NLS-1$
ImageDescriptor imgDesc = UIPlugin.getImageDescriptor(key);
if (imgDesc == null) {
String dir = System.getProperty("work.dir"); //$NON-NLS-1$
if (dir == null) dir = System.getProperty("java.home"); //$NON-NLS-1$
File mirror = null;
if (dir != null) mirror = new File(dir);
else mirror = new File("."); //$NON-NLS-1$
File imgFile = getTempImg("_directory_"); //$NON-NLS-1$
createImage(key, mirror, imgFile);
}
return UIPlugin.getImage(key);
}
/**
* Get the temporary directory store the images and temporary mirror files.
* @return
*/
protected File getTempDir() {
File cacheRoot = ModelManager.getCacheRoot();
File tempDir = new File(cacheRoot, ".tmp"); //$NON-NLS-1$
if (!tempDir.exists() && !tempDir.mkdirs()) {
tempDir = cacheRoot;
}
return tempDir;
}
/**
* Get the an image file named "imgName" in the temporary image
* directory.
*
* @param imgName The image's file name.
* @return The file object of this image file.
*/
protected File getTempImg(String imgName) {
File tempDir = getTempDir();
File imgDir = new File(tempDir, ".img"); //$NON-NLS-1$
if (!imgDir.exists() && !imgDir.mkdirs()) {
imgDir = tempDir;
}
return new File(imgDir, imgName + ".png"); //$NON-NLS-1$
}
/**
* Create an image file using "png" format
* for the specified temporary file.
*
* @param icon The icon that is used for the temporary file.
* @param tmpfile The temporary file.
*/
private void createImageFromIcon(Icon icon, File imgFile) {
BufferedImage bi = new BufferedImage(icon.getIconWidth(), icon.getIconHeight(), BufferedImage.TYPE_4BYTE_ABGR);
Graphics g = bi.createGraphics();
icon.paintIcon(dummyComponent, g, 0, 0);
g.dispose();
try {
ImageIO.write(bi, "png", imgFile); //$NON-NLS-1$
}
catch (IOException e) {
}
}
/**
* Send a notification to inform the file tree for changed images.
*
* @param node The node whose image has changed.
* @param key The key used to store the images.
* @param oldImg The old image descriptor.
* @param newImg The new image descriptor.
*/
private void sendNotification(IFSTreeNode node, String key, ImageDescriptor oldImg, ImageDescriptor newImg) {
if (node.getPeerNode() != null) {
IPropertyChangeProvider viewerInput = (IPropertyChangeProvider) node.getPeerNode().getAdapter(IPropertyChangeProvider.class);
viewerInput.firePropertyChange(new PropertyChangeEvent(node, key, oldImg, newImg));
}
}
}