package org.csstudio.sds.ui.thumbnail; import java.io.File; import java.io.FileFilter; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.csstudio.sds.ui.DisplayInfoService; import org.eclipse.core.resources.IResourceChangeEvent; import org.eclipse.core.resources.IResourceChangeListener; import org.eclipse.core.resources.IResourceDelta; import org.eclipse.core.resources.IWorkspace; import org.eclipse.core.resources.IWorkspaceRoot; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.Path; import org.eclipse.nebula.widgets.gallery.AbstractGalleryItemRenderer; import org.eclipse.nebula.widgets.gallery.AbstractGridGroupRenderer; import org.eclipse.nebula.widgets.gallery.DefaultGalleryGroupRenderer; import org.eclipse.nebula.widgets.gallery.DefaultGalleryItemRenderer; import org.eclipse.nebula.widgets.gallery.Gallery; import org.eclipse.nebula.widgets.gallery.GalleryItem; import org.eclipse.nebula.widgets.gallery.ListItemRenderer; import org.eclipse.nebula.widgets.gallery.NoGroupRenderer; import org.eclipse.swt.SWT; import org.eclipse.swt.SWTException; import org.eclipse.swt.events.ControlAdapter; import org.eclipse.swt.events.ControlEvent; import org.eclipse.swt.events.MouseListener; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.events.SelectionListener; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.graphics.ImageData; import org.eclipse.swt.layout.FillLayout; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Display; public class SdsThumbnailPanel extends Composite { public enum LibraryPanelLayout { GroupedGrid, UngroupedGrid, UngroupedList; } private List<LibraryPanelListener> listeners; private Gallery gallery; private List<File> sortedDisplays = new ArrayList<File>(); private Map<File, GalleryItem> displayFileToGalleryItemMap = new HashMap<File, GalleryItem>(); private Map<GalleryItem, File> galleryItemToDisplayFileMap = new HashMap<GalleryItem, File>(); private List<File> folderList; private final DisplayInfoService displayInfoService = new DisplayInfoService(); private IResourceChangeListener resourceChangeListener; private ThumbnailCreationRunnable currentThumbnailCreationRunnable; public SdsThumbnailPanel(Composite parent, int style, LibraryPanelLayout libraryLayout) { super(parent, style); this.listeners = new ArrayList<SdsThumbnailPanel.LibraryPanelListener>(); setLayout(new FillLayout()); gallery = new Gallery(this, SWT.V_SCROLL | SWT.SINGLE); setLibraryLayout(libraryLayout); gallery.addSelectionListener(new SelectionListener() { @Override public void widgetSelected(SelectionEvent e) { fireSelectionChanged(); } @Override public void widgetDefaultSelected(SelectionEvent e) { fireSelectionChanged(); } }); initResourceListener(); } public void addLibraryPanelListener(LibraryPanelListener listener) { assert listener != null : "Precondition failed: listener != null"; this.listeners.add(listener); } public void removeLibraryPanelListener(LibraryPanelListener listener) { assert listener != null : "Precondition failed: listener != null"; this.listeners.remove(listener); } @Override public void addMouseListener(MouseListener mouseListener) { this.gallery.addMouseListener(mouseListener); } @Override public void removeMouseListener(MouseListener mouseListener) { this.gallery.removeMouseListener(mouseListener); } public void setLibraryLayout(LibraryPanelLayout layout) { assert layout != null : "Precondition failed: layout != null"; AbstractGalleryItemRenderer itemRenderer = null; final AbstractGridGroupRenderer groupRenderer; int itemHeight = 120; switch (layout) { case GroupedGrid: itemRenderer = new DefaultGalleryItemRenderer(); groupRenderer = new DefaultGalleryGroupRenderer(); break; case UngroupedGrid: itemRenderer = new DefaultGalleryItemRenderer(); groupRenderer = new NoGroupRenderer(); break; case UngroupedList: itemRenderer = new ListItemRenderer(); itemHeight = 20; groupRenderer = new NoGroupRenderer(); gallery.addControlListener(new ControlAdapter() { @Override public void controlResized(ControlEvent e) { int newWidth = gallery.getClientArea().width; if (newWidth > 0) { groupRenderer.setItemWidth(newWidth); } } }); break; default: itemRenderer = new DefaultGalleryItemRenderer(); groupRenderer = new DefaultGalleryGroupRenderer(); break; } groupRenderer.setItemHeight(itemHeight); groupRenderer.setItemWidth(100); groupRenderer.setAutoMargin(true); gallery.setGroupRenderer(groupRenderer); gallery.setItemRenderer(itemRenderer); } public Gallery getGallery() { return gallery; } public File getSelectedFile() { GalleryItem selected = getSelected(); return selected != null ? galleryItemToDisplayFileMap.get(selected) : null; } public void select(int groupIndex, int index) { assert index < getItemCount(groupIndex) : "Precondition failed: index < getItemCount(" + groupIndex + ")"; if (groupIndex > -1 && index > -1) { GalleryItem group = gallery.getItem(groupIndex); gallery.setSelection(new GalleryItem[] { group.getItem(index) }); } else { gallery.deselectAll(); } } public int getSelectionIndex() { int result = -1; if (gallery.getSelectionCount() > 0) { result = gallery.indexOf(getSelected()); } return result; } public int getSelectionGroupIndex() { int result = -1; if (gallery.getSelectionCount() > 0) { result = gallery.indexOf(getSelected().getParentItem()); } return result; } public int getItemCount(int groupIndex) { return gallery.getItem(groupIndex).getItemCount(); } public void setFolders(List<File> folderList) { assert folderList != null : "Precondition failed: folderList != null"; this.folderList = folderList; sortedDisplays.clear(); displayFileToGalleryItemMap.clear(); galleryItemToDisplayFileMap.clear(); gallery.clearAll(); gallery.removeAll(); for (File folder : folderList) { if(folder.exists()) { String text = getWorkspaceRelativePath(folder); final GalleryItem folderGroupItem = new GalleryItem(gallery, SWT.NONE); folderGroupItem.setText(text); folderGroupItem.setExpanded(true); FileFilter fileFilter = new FileFilter() { @Override public boolean accept(File pathname) { return pathname.isFile() && pathname.getName().endsWith(".css-sds"); } }; for (File file : folder.listFiles(fileFilter)) { GalleryItem galleryItem = new GalleryItem(folderGroupItem, SWT.NONE); galleryItem.setText(file.getName().substring(0, file.getName().lastIndexOf("."))); addFileToLibrary(file, galleryItem); } } } fireSelectionChanged(); createThumbnailsAsync(); } @Override public void dispose() { ResourcesPlugin.getWorkspace().removeResourceChangeListener( resourceChangeListener); super.dispose(); } private void fireSelectionChanged() { for (LibraryPanelListener listener : listeners) { listener.onSelectionChanged(this); } } private void initResourceListener() { resourceChangeListener = new IResourceChangeListener() { @Override public void resourceChanged(IResourceChangeEvent event) { boolean relevantChange = false; IResourceDelta rootDelta = event.getDelta(); for (File folder : folderList) { IResourceDelta folderDelta = rootDelta.findMember(new Path( getWorkspaceRelativePath(folder))); if (folderDelta != null) { // if (folderDelta.getKind() == IResourceDelta.REMOVED // || folderDelta.getKind() == IResourceDelta.MOVED_TO) // { // force complete update relevantChange = true; // return; // } // // handleFolderChanged(folderDelta); } } if (relevantChange) { Display.getDefault().asyncExec(new Runnable() { @Override public void run() { setFolders(folderList); } }); } } // private void handleFolderChanged(IResourceDelta folderDelta) { // // try { // folderDelta.accept(new IResourceDeltaVisitor() { // public boolean visit(IResourceDelta delta) { // // IResource resource = delta.getResource(); // // only interested in files with the "txt" extension // // if (resource.getType() == IResource.FILE // && "css-sds".equalsIgnoreCase(resource // .getFileExtension())) { // // if (resource.exists()) { // // resource.get // // } // // } // return true; // } // }); // } catch (CoreException e) { // // open error dialog with syncExec or print to plugin log // // file // } // } }; ResourcesPlugin.getWorkspace().addResourceChangeListener( resourceChangeListener, IResourceChangeEvent.POST_CHANGE); } private GalleryItem getSelected() { GalleryItem[] selection = gallery.getSelection(); if (selection != null && selection.length > 0) { return selection[0]; } else { return null; } } private String getWorkspaceRelativePath(File folder) { IWorkspace workspace = ResourcesPlugin.getWorkspace(); IWorkspaceRoot root = workspace.getRoot(); IPath rootPath = root.getLocation(); Path path = new Path(folder.getAbsolutePath()); return path.makeRelativeTo(rootPath).toString(); } private void addFileToLibrary(File file, GalleryItem galleryItem) { sortedDisplays.add(file); displayFileToGalleryItemMap.put(file, galleryItem); galleryItemToDisplayFileMap.put(galleryItem, file); } private void createThumbnailsAsync() { final Display display = Display.getDefault(); final ArrayList<File> displayListCopy = new ArrayList<File>(sortedDisplays); if(currentThumbnailCreationRunnable != null) { currentThumbnailCreationRunnable.cancel(); } currentThumbnailCreationRunnable = new ThumbnailCreationRunnable(displayListCopy, display); new Thread(currentThumbnailCreationRunnable).start(); } public interface LibraryPanelListener { void onSelectionChanged(SdsThumbnailPanel libraryPanel); } private class ThumbnailCreationRunnable implements Runnable { private final List<File> displayList; private final Display display; private boolean isCanceled = false; public ThumbnailCreationRunnable(List<File> displayList, Display display) { this.displayList = displayList; this.display = display; } public void cancel() { this.isCanceled = true; } @Override public void run() { for (int fileIndex = 0; fileIndex < displayList.size() && !isCanceled; fileIndex++) { final File file = displayList.get(fileIndex); final ImageData imageData = displayInfoService.getImage(file); if (!display.isDisposed()) { display.syncExec(new Runnable() { @Override public void run() { Image image = null; try { GalleryItem item = displayFileToGalleryItemMap .get(file); if (item != null && !display.isDisposed()) { image = new Image(display, imageData); if (!item.isDisposed()) { item.setImage(image); } } } catch (SWTException swtException) { if (image != null) { image.dispose(); } } } }); } } } } }