/** @author <a href="mailto:[email protected]">Konstantin Komissarchik</a> */ public final class ContactImageService extends ImageService { private static final ImageServiceData IMG_PERSON = new ImageServiceData(ImageData.readFromClassLoader(Contact.class, "Contact.png")); private static final ImageServiceData IMG_PERSON_FADED = new ImageServiceData(ImageData.readFromClassLoader(Contact.class, "ContactFaded.png")); private Listener listener; @Override protected void initImageService() { this.listener = new FilteredListener<PropertyContentEvent>() { @Override protected void handleTypedEvent(final PropertyContentEvent event) { refresh(); } }; context(IModelElement.class).attach(this.listener, "EMail"); } @Override protected ImageServiceData compute() { if (context(Contact.class).getEMail().getContent() == null) { return IMG_PERSON_FADED; } else { return IMG_PERSON; } } @Override public void dispose() { super.dispose(); context(IModelElement.class).detach(this.listener, "EMail"); } }
/** @author <a href="mailto:[email protected]">Konstantin Komissarchik</a> */ public class RelativePathBrowseActionHandler extends SapphireBrowseActionHandler { private static final ImageData IMG_FILE = ImageData.createFromClassLoader(RelativePathBrowseActionHandler.class, "File.png"); private static final ImageData IMG_FOLDER = ImageData.createFromClassLoader(RelativePathBrowseActionHandler.class, "Folder.png"); public static final String ID = "Sapphire.Browse.Path.Relative"; public static final String PARAM_TYPE = "type"; public static final String PARAM_EXTENSIONS = "extensions"; public static final String PARAM_LEADING_SLASH = "leading-slash"; private FileExtensionsService fileExtensionService; private List<String> staticFileExtensionsList; private FileSystemResourceType type; private boolean includeLeadingSlash; @Override public void init(final SapphireAction action, final ActionHandlerDef def) { super.init(action, def); setId(ID); setLabel(Resources.label); addImage(IMG_FILE); final Property property = property(); this.type = null; final String paramType = def.getParam(PARAM_TYPE); if (paramType != null) { if (paramType.equalsIgnoreCase("file")) { this.type = FileSystemResourceType.FILE; } else if (paramType.equalsIgnoreCase("folder")) { this.type = FileSystemResourceType.FOLDER; } } else { final ValidFileSystemResourceType validFileSystemResourceTypeAnnotation = property.definition().getAnnotation(ValidFileSystemResourceType.class); if (validFileSystemResourceTypeAnnotation != null) { this.type = validFileSystemResourceTypeAnnotation.value(); } } final String staticFileExtensions = def.getParam(PARAM_EXTENSIONS); if (staticFileExtensions == null) { this.fileExtensionService = property.service(FileExtensionsService.class); if (this.fileExtensionService == null) { this.staticFileExtensionsList = Collections.emptyList(); } } else { this.staticFileExtensionsList = new ArrayList<String>(); for (String extension : staticFileExtensions.split(",")) { extension = extension.trim(); if (extension.length() > 0) { this.staticFileExtensionsList.add(extension); } } } final String paramLeadingSlash = def.getParam(PARAM_LEADING_SLASH); if (paramLeadingSlash != null) { this.includeLeadingSlash = Boolean.parseBoolean(paramLeadingSlash); } else { this.includeLeadingSlash = false; } } @Override protected String browse(final SapphireRenderingContext context) { final Property property = property(); final List<Path> roots = getBasePaths(); String selectedAbsolutePath = null; final List<String> extensions; if (this.fileExtensionService == null) { extensions = this.staticFileExtensionsList; } else { extensions = this.fileExtensionService.extensions(); } if (enclosed()) { final List<IContainer> baseContainers = new ArrayList<IContainer>(); for (Path path : roots) { final IContainer baseContainer = getWorkspaceContainer(path.toFile()); if (baseContainer != null) { baseContainers.add(baseContainer); } else { break; } } final ITreeContentProvider contentProvider; final ILabelProvider labelProvider; final ViewerComparator viewerComparator; final Object input; if (roots.size() == baseContainers.size()) { // All paths are in the Eclipse Workspace. Use the available content and label // providers. contentProvider = new WorkspaceContentProvider(baseContainers); labelProvider = new WorkbenchLabelProvider(); viewerComparator = new ResourceComparator(); input = ResourcesPlugin.getWorkspace().getRoot(); } else { // At least one of the roots is not in the Eclipse Workspace. Use custom file // system content and label providers. contentProvider = new FileSystemContentProvider(roots); labelProvider = new FileSystemLabelProvider(context); viewerComparator = new FileSystemNodeComparator(); input = new Object(); } final ElementTreeSelectionDialog dialog = new ElementTreeSelectionDialog(context.getShell(), labelProvider, contentProvider); dialog.setTitle(property.definition().getLabel(false, CapitalizationType.TITLE_STYLE, false)); dialog.setMessage( createBrowseDialogMessage( property.definition().getLabel(true, CapitalizationType.NO_CAPS, false))); dialog.setAllowMultiple(false); dialog.setHelpAvailable(false); dialog.setInput(input); dialog.setComparator(viewerComparator); final Path currentPathAbsolute = convertToAbsolute((Path) ((Value<?>) property).content()); if (currentPathAbsolute != null) { Object initialSelection = null; if (contentProvider instanceof WorkspaceContentProvider) { final URI uri = currentPathAbsolute.toFile().toURI(); final IWorkspaceRoot wsroot = ResourcesPlugin.getWorkspace().getRoot(); final IFile[] files = wsroot.findFilesForLocationURI(uri); if (files.length > 0) { final IFile file = files[0]; if (file.exists()) { initialSelection = file; } } if (initialSelection == null) { final IContainer[] containers = wsroot.findContainersForLocationURI(uri); if (containers.length > 0) { final IContainer container = containers[0]; if (container.exists()) { initialSelection = container; } } } } else { initialSelection = ((FileSystemContentProvider) contentProvider).find(currentPathAbsolute); } if (initialSelection != null) { dialog.setInitialSelection(initialSelection); } } if (this.type == FileSystemResourceType.FILE) { dialog.setValidator(new FileSelectionStatusValidator()); } else if (this.type == FileSystemResourceType.FOLDER) { dialog.addFilter(new ContainersOnlyViewerFilter()); } if (!extensions.isEmpty()) { dialog.addFilter(new ExtensionBasedViewerFilter(extensions)); } if (dialog.open() == Window.OK) { final Object firstResult = dialog.getFirstResult(); if (firstResult instanceof IResource) { selectedAbsolutePath = ((IResource) firstResult).getLocation().toString(); } else { selectedAbsolutePath = ((FileSystemNode) firstResult).getFile().getPath(); } } } else if (this.type == FileSystemResourceType.FOLDER) { final DirectoryDialog dialog = new DirectoryDialog(context.getShell()); dialog.setText( property.definition().getLabel(true, CapitalizationType.FIRST_WORD_ONLY, false)); dialog.setMessage( createBrowseDialogMessage( property.definition().getLabel(true, CapitalizationType.NO_CAPS, false))); final Value<?> value = (Value<?>) property; final Path path = (Path) value.content(); if (path != null) { dialog.setFilterPath(path.toOSString()); } else if (roots.size() > 0) { dialog.setFilterPath(roots.get(0).toOSString()); } selectedAbsolutePath = dialog.open(); } else { final FileDialog dialog = new FileDialog(context.getShell()); dialog.setText( property.definition().getLabel(true, CapitalizationType.FIRST_WORD_ONLY, false)); final Value<?> value = (Value<?>) property; final Path path = (Path) value.content(); if (path != null && path.segmentCount() > 1) { dialog.setFilterPath(path.removeLastSegments(1).toOSString()); dialog.setFileName(path.lastSegment()); } else if (roots.size() > 0) { dialog.setFilterPath(roots.get(0).toOSString()); } if (!extensions.isEmpty()) { final StringBuilder buf = new StringBuilder(); for (String extension : extensions) { if (buf.length() > 0) { buf.append(';'); } buf.append("*."); buf.append(extension); } dialog.setFilterExtensions(new String[] {buf.toString()}); } selectedAbsolutePath = dialog.open(); } if (selectedAbsolutePath != null) { final Path relativePath = convertToRelative(new Path(selectedAbsolutePath)); if (relativePath != null) { String result = relativePath.toPortableString(); if (this.includeLeadingSlash) { result = "/" + result; } return result; } } return null; } protected List<Path> getBasePaths() { return property().service(RelativePathService.class).roots(); } protected boolean enclosed() { final RelativePathService service = property().service(RelativePathService.class); if (service == null) { return true; } else { return service.enclosed(); } } protected Path convertToRelative(final Path path) { if (path != null) { final RelativePathService service = property().service(RelativePathService.class); if (service == null) { if (enclosed()) { for (Path root : getBasePaths()) { if (root.isPrefixOf(path)) { return path.makeRelativeTo(root); } } } else { final String pathDevice = path.getDevice(); for (Path root : getBasePaths()) { if (MiscUtil.equal(pathDevice, root.getDevice())) { return path.makeRelativeTo(root); } } } } else { return service.convertToRelative(path); } } return null; } protected Path convertToAbsolute(final Path path) { if (path != null) { final RelativePathService service = property().service(RelativePathService.class); if (service == null) { if (enclosed() && path.segmentCount() > 0 && path.segment(0).equals("..")) { return null; } Path absolute = null; for (Path root : getBasePaths()) { try { final File file = root.append(path).toFile().getCanonicalFile(); absolute = new Path(file.getPath()); if (file.exists()) { break; } } catch (IOException e) { // Intentionally ignoring to continue to the next root. If none of the roots // produce a viable absolute path, a null return from this method signifies // being unable to convert the relative path. That is sufficient. } } return absolute; } else { return service.convertToAbsolute(path); } } return null; } private static String getFileExtension(final String fileName) { if (fileName == null) { return null; } int dotIndex = fileName.lastIndexOf('.'); if (dotIndex < 0) { return null; } return fileName.substring(dotIndex + 1); } private static IContainer getWorkspaceContainer(final File f) { final IWorkspaceRoot wsroot = ResourcesPlugin.getWorkspace().getRoot(); final IContainer[] wsContainers = wsroot.findContainersForLocationURI(f.toURI()); if (wsContainers.length > 0) { return wsContainers[0]; } return null; } public static final class ContainersOnlyViewerFilter extends ViewerFilter { public boolean select(final Viewer viewer, final Object parent, final Object element) { return (element instanceof IContainer || (element instanceof FileSystemNode && ((FileSystemNode) element).getFile().isDirectory())); } } public static final class ExtensionBasedViewerFilter extends ViewerFilter { private List<String> extensions; public ExtensionBasedViewerFilter(final List<String> extensions) { change(extensions); } public void change(final List<String> extensions) { this.extensions = new ArrayList<String>(extensions); } public boolean select(final Viewer viewer, final Object parent, final Object element) { if (element instanceof IFile || (element instanceof FileSystemNode && ((FileSystemNode) element).getFile().isFile())) { final String extension; if (element instanceof IFile) { extension = ((IFile) element).getFileExtension(); } else { extension = getFileExtension(((FileSystemNode) element).getFile().getName()); } if (extension != null && extension.length() != 0) { for (String ext : this.extensions) { if (extension.equalsIgnoreCase(ext)) { return true; } } } return false; } else if (element instanceof IContainer) { if (element instanceof IProject && !((IProject) element).isOpen()) { return false; } return true; } return true; } } private static final class FileSelectionStatusValidator implements ISelectionStatusValidator { private static final IStatus ERROR_STATUS = new Status(IStatus.ERROR, SapphireUiFrameworkPlugin.PLUGIN_ID, MiscUtil.EMPTY_STRING); private static final IStatus OK_STATUS = new Status(IStatus.OK, SapphireUiFrameworkPlugin.PLUGIN_ID, MiscUtil.EMPTY_STRING); public IStatus validate(final Object[] selection) { if (selection.length == 1) { final Object sel = selection[0]; if (sel instanceof IFile || (sel instanceof FileSystemNode && ((FileSystemNode) sel).getFile().isFile())) { return OK_STATUS; } } return ERROR_STATUS; } } private static final class WorkspaceContentProvider extends WorkbenchContentProvider { private final List<IContainer> roots; public WorkspaceContentProvider(final List<IContainer> roots) { this.roots = roots; } @Override public Object[] getElements(final Object element) { final List<IResource> elements = new ArrayList<IResource>(); if (this.roots.size() == 1) { final IContainer root = this.roots.get(0); try { for (IResource child : root.members()) { if (child.isAccessible()) { elements.add(child); } } } catch (CoreException e) { SapphireUiFrameworkPlugin.log(e); } } else { elements.addAll(this.roots); } return elements.toArray(new IResource[elements.size()]); } @Override public Object getParent(final Object element) { if ((this.roots.contains(element)) || (this.roots.size() == 1 && this.roots.contains(((IResource) element).getParent()))) { return null; } else { return super.getParent(element); } } } private static final class FileSystemNode { private final File file; private final FileSystemNode parent; private Map<File, FileSystemNode> children; public FileSystemNode(final File file, final FileSystemNode parent) { this.file = file; this.parent = parent; this.children = Collections.emptyMap(); } public File getFile() { return this.file; } public FileSystemNode getParent() { return this.parent; } public boolean hasChildren() { return this.file.isDirectory(); } public FileSystemNode[] getChildren() { if (this.file.isDirectory()) { final File[] directoryListing = this.file.listFiles(); if (directoryListing != null && directoryListing.length > 0) { final FileSystemNode[] result = new FileSystemNode[directoryListing.length]; final Map<File, FileSystemNode> newChildrenMap = new HashMap<File, FileSystemNode>(); for (int i = 0, n = directoryListing.length; i < n; i++) { final File f = directoryListing[i]; FileSystemNode node = this.children.get(f); if (node == null) { node = new FileSystemNode(f, this); } newChildrenMap.put(f, node); result[i] = node; } this.children = newChildrenMap; return result; } } return new FileSystemNode[0]; } public FileSystemNode find(final Path path) { final int pathSegmentCount = path.segmentCount(); if (pathSegmentCount == 0) { return this; } else { final String firstSegment = path.segment(0); for (FileSystemNode child : getChildren()) { if (child.getFile().getName().equals(firstSegment)) { return child.find(path.removeFirstSegments(1)); } } return null; } } } private static final class FileSystemContentProvider implements ITreeContentProvider { private final FileSystemNode[] roots; public FileSystemContentProvider(final List<Path> roots) { this.roots = new FileSystemNode[roots.size()]; for (int i = 0, n = roots.size(); i < n; i++) { this.roots[i] = new FileSystemNode(roots.get(i).toFile(), null); } } public FileSystemNode find(final Path path) { for (FileSystemNode root : this.roots) { final Path rootPath = new Path(root.getFile().getPath()); if (rootPath.isPrefixOf(path)) { return root.find(path.makeRelativeTo(rootPath)); } } return null; } public Object[] getElements(final Object element) { return this.roots; } public Object getParent(final Object element) { return ((FileSystemNode) element).getParent(); } public Object[] getChildren(final Object element) { return ((FileSystemNode) element).getChildren(); } public boolean hasChildren(Object element) { return ((FileSystemNode) element).hasChildren(); } public void inputChanged(final Viewer viewer, final Object oldInput, final Object newInput) {} public void dispose() {} } private static final class FileSystemLabelProvider extends LabelProvider { private final SapphireRenderingContext context; public FileSystemLabelProvider(final SapphireRenderingContext context) { this.context = context; } @Override public String getText(final Object element) { return ((FileSystemNode) element).getFile().getName(); } @Override public Image getImage(final Object element) { if (((FileSystemNode) element).getFile().isDirectory()) { return this.context.getImageCache().image(IMG_FOLDER); } else { return this.context.getImageCache().image(IMG_FILE); } } } private static final class FileSystemNodeComparator extends ViewerComparator { @SuppressWarnings("unchecked") public int compare(final Viewer viewer, final Object obj1, final Object obj2) { final File f1 = ((FileSystemNode) obj1).getFile(); final File f2 = ((FileSystemNode) obj2).getFile(); final boolean isFile1Directory = f1.isDirectory(); final boolean isFile2Directory = f2.isDirectory(); if (isFile1Directory == isFile2Directory) { return Policy.getComparator().compare(f1.getName(), f2.getName()); } else if (isFile1Directory) { return -1; } else { return 1; } } } public static final class ResourceComparator extends ViewerComparator { @SuppressWarnings("unchecked") public int compare(final Viewer viewer, final Object obj1, final Object obj2) { final IResource r1 = (IResource) obj1; final IResource r2 = (IResource) obj2; final boolean isResource1Container = (r1 instanceof IContainer); final boolean isResource2Container = (r2 instanceof IContainer); if (isResource1Container == isResource2Container) { return Policy.getComparator().compare(r1.getName(), r2.getName()); } else if (isResource1Container) { return -1; } else { return 1; } } } private static final class Resources extends NLS { public static String label; static { initializeMessages(RelativePathBrowseActionHandler.class.getName(), Resources.class); } } }