Download
Getting Started
Members
Projects
Community
Marketplace
Events
Planet Eclipse
Newsletter
Videos
Participate
Report a Bug
Forums
Mailing Lists
Wiki
IRC
How to Contribute
Working Groups
Automotive
Internet of Things
LocationTech
Long-Term Support
PolarSys
Science
OpenMDM
More
Community
Marketplace
Events
Planet Eclipse
Newsletter
Videos
Participate
Report a Bug
Forums
Mailing Lists
Wiki
IRC
How to Contribute
Working Groups
Automotive
Internet of Things
LocationTech
Long-Term Support
PolarSys
Science
OpenMDM
Toggle navigation
Bugzilla – Attachment 193433 Details for
Bug 341685
Accessibility: JAWS should read description of graphics, and column headers in tables and trees.
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
Log In
[x]
|
Terms of Use
|
Copyright Agent
[patch]
Revised fix for this bug, includes NLS support for icon labels.
Bug341685patch_V2.txt (text/plain), 50.46 KB, created by
Jonathan Lawrence
on 2011-04-17 10:10:59 EDT
(
hide
)
Description:
Revised fix for this bug, includes NLS support for icon labels.
Filename:
MIME Type:
Creator:
Jonathan Lawrence
Created:
2011-04-17 10:10:59 EDT
Size:
50.46 KB
patch
obsolete
>Index: src/org/eclipse/mat/ui/iconlabels.properties >=================================================================== >--- src/org/eclipse/mat/ui/iconlabels.properties (revision 0) >+++ src/org/eclipse/mat/ui/iconlabels.properties (revision 0) >@@ -0,0 +1,147 @@ >+# NLS_MESSAGEFORMAT_NONE >+# NLS_ENCODING=UNICODE >+# >+ >+# This file is automatically generated by org.eclipse.mat.ui.MemoryAnalyserPlugin.main(). >+# Refer to the documentation/comments for this method for usage instructions. >+# >+# Any manual modifications to this file will need to be reapplied if the file is regenerated. >+# Therefore it is preferable if such modifications are kept to a minimum, or preferably >+# achieved by amending the label generation code in MemoryAnalyserPlugin.buildIconLabel(). >+# >+ >+# Icon label property to be used for an unknown icon: >+IconLabelUnknown=unknown icon >+ >+# Automatically generated icon label properties: >+IconLabel-acquire=acquire >+IconLabel-as_histogram=as histogram >+IconLabel-calculator=calculator >+IconLabel-class_refs_inbound=class refs inbound >+IconLabel-class_refs_outbound=class refs outbound >+IconLabel-close_branch=close branch >+IconLabel-close_pane=close pane >+IconLabel-compare=compare >+IconLabel-copy=copy >+IconLabel-decorations-gc_root=gc root >+IconLabel-decorations-in=in >+IconLabel-decorations-out=out >+IconLabel-dominator_tree=dominator tree >+IconLabel-execute_query=execute query >+IconLabel-expert=expert >+IconLabel-explore=explore >+IconLabel-export=export >+IconLabel-export_csv=export csv >+IconLabel-export_html=export html >+IconLabel-export_txt=export txt >+IconLabel-fill_arguments_wiz=fill arguments wiz >+IconLabel-filter=filter >+IconLabel-finalizer=finalizer >+IconLabel-find=find >+IconLabel-grouping=grouping >+IconLabel-heapdump_details=heapdump details >+IconLabel-heapdump_history=heapdump history >+IconLabel-heapobjects-array_obj=array object >+IconLabel-heapobjects-array_obj_gc_root=array object gc root >+IconLabel-heapobjects-class=class >+IconLabel-heapobjects-class_mixed=class mixed >+IconLabel-heapobjects-class_obj=class object >+IconLabel-heapobjects-class_obj_gc_root=class object gc root >+IconLabel-heapobjects-class_old=class old >+IconLabel-heapobjects-classloader_obj=classloader object >+IconLabel-heapobjects-classloader_obj_gc_root=classloader object gc root >+IconLabel-heapobjects-heapdump16=heapdump16 >+IconLabel-heapobjects-in-array_obj=array object in >+IconLabel-heapobjects-in-array_obj_gc_root=array object gc root in >+IconLabel-heapobjects-in-class=class in >+IconLabel-heapobjects-in-class_in_old=class in old in >+IconLabel-heapobjects-in-class_mixed=class mixed in >+IconLabel-heapobjects-in-class_obj=class object in >+IconLabel-heapobjects-in-class_obj_gc_root=class object gc root in >+IconLabel-heapobjects-in-classloader_obj=classloader object in >+IconLabel-heapobjects-in-classloader_obj_gc_root=classloader object gc root in >+IconLabel-heapobjects-in-instance_obj=instance object in >+IconLabel-heapobjects-in-instance_obj_gc_root=instance object gc root in >+IconLabel-heapobjects-instance_obj=instance object >+IconLabel-heapobjects-instance_obj_gc_root=instance object gc root >+IconLabel-heapobjects-out-array_obj=array object out >+IconLabel-heapobjects-out-array_obj_gc_root=array object gc root out >+IconLabel-heapobjects-out-class=class out >+IconLabel-heapobjects-out-class_mixed=class mixed out >+IconLabel-heapobjects-out-class_obj=class object out >+IconLabel-heapobjects-out-class_obj_gc_root=class object gc root out >+IconLabel-heapobjects-out-class_out_old=class out old out >+IconLabel-heapobjects-out-classloader_obj=classloader object out >+IconLabel-heapobjects-out-classloader_obj_gc_root=classloader object gc root out >+IconLabel-heapobjects-out-instance_obj=instance object out >+IconLabel-heapobjects-out-instance_obj_gc_root=instance object gc root out >+IconLabel-heapobjects-package=package >+IconLabel-heapobjects-superclass=superclass >+IconLabel-help=help >+IconLabel-id=id >+IconLabel-immediate_dominators=immediate dominators >+IconLabel-import_report=import report >+IconLabel-info=info >+IconLabel-inspector_view=inspector view >+IconLabel-list_inbound=list inbound >+IconLabel-list_outbound=list outbound >+IconLabel-memory_analyzer_32=memory analyzer 32 >+IconLabel-memory_analyzer_perspective=memory analyzer perspective >+IconLabel-misc-sum=sum >+IconLabel-misc-sum_plus=sum plus >+IconLabel-move_down=move down >+IconLabel-move_up=move up >+IconLabel-mpaths_from_gc=merge paths from gc >+IconLabel-mpaths_from_gc_by_class=merge paths from gc by class >+IconLabel-mpaths_to_gc_by_class=merge paths to gc by class >+IconLabel-navigator_view=navigator view >+IconLabel-notepad=notepad >+IconLabel-open_snapshot=open snapshot >+IconLabel-oql=oql >+IconLabel-osgi-attr_xml_obj=attribute xml object >+IconLabel-osgi-bundle=bundle >+IconLabel-osgi-dependencies=dependencies >+IconLabel-osgi-dependents=dependents >+IconLabel-osgi-ext_point_obj=extension point object >+IconLabel-osgi-ext_points_obj=extension points object >+IconLabel-osgi-extension_obj=extension object >+IconLabel-osgi-extensions_obj=extensions object >+IconLabel-osgi-frgmt_obj=fragment object >+IconLabel-osgi-frgmts_obj=fragments object >+IconLabel-osgi-generic_xml_obj=generic xml object >+IconLabel-osgi-int_obj=int object >+IconLabel-osgi-location=location >+IconLabel-osgi-property=property >+IconLabel-osgi-registered_services=registered services >+IconLabel-osgi-registry=registry >+IconLabel-osgi-used_services=used services >+IconLabel-package=package >+IconLabel-path2gc=path2gc >+IconLabel-percentage=percentage >+IconLabel-pinned=pinned >+IconLabel-plus=plus >+IconLabel-query=query >+IconLabel-query_browser=query browser >+IconLabel-query_disabled=query disabled >+IconLabel-refresh=refresh >+IconLabel-refreshing=refreshing >+IconLabel-remove=remove >+IconLabel-remove_console=remove console >+IconLabel-removeall=removeall >+IconLabel-retainedSet=retainedSet >+IconLabel-roots=roots >+IconLabel-save=save >+IconLabel-select_table=select table >+IconLabel-set_differenceA=set differenceA >+IconLabel-set_differenceB=set differenceB >+IconLabel-set_intersection=set intersection >+IconLabel-set_symmetric_difference=set symmetric difference >+IconLabel-set_union=set union >+IconLabel-show_histogram=show histogram >+IconLabel-show_pane=show pane >+IconLabel-show_retained_set=show retained set >+IconLabel-size=size >+IconLabel-synced=synced >+IconLabel-synced_disabled=synced disabled >+IconLabel-thread=thread >+IconLabel-threads=threads >Index: src/org/eclipse/mat/ui/internal/browser/QueryBrowserPopup.java >=================================================================== >--- src/org/eclipse/mat/ui/internal/browser/QueryBrowserPopup.java (revision 1101) >+++ src/org/eclipse/mat/ui/internal/browser/QueryBrowserPopup.java (working copy) >@@ -38,6 +38,7 @@ > import org.eclipse.mat.ui.MemoryAnalyserPlugin; > import org.eclipse.mat.ui.Messages; > import org.eclipse.mat.ui.QueryExecution; >+import org.eclipse.mat.ui.accessibility.AccessibleCompositeAdapter; > import org.eclipse.mat.ui.editor.MultiPaneEditor; > import org.eclipse.mat.ui.util.ErrorHelper; > import org.eclipse.mat.ui.util.IPolicy; >@@ -222,6 +223,7 @@ > textLayout.setFont(table.getFont()); > textLayout.setText(Messages.QueryBrowserPopup_Categories); > textLayout.setFont(boldFont); >+ AccessibleCompositeAdapter.access(table); > > tableColumnLayout.setColumnData(new TableColumn(table, SWT.NONE), new ColumnWeightData(100, 100)); > table.getShell().addControlListener(new ControlAdapter() >Index: src/org/eclipse/mat/ui/internal/query/arguments/ArgumentsTable.java >=================================================================== >--- src/org/eclipse/mat/ui/internal/query/arguments/ArgumentsTable.java (revision 1101) >+++ src/org/eclipse/mat/ui/internal/query/arguments/ArgumentsTable.java (working copy) >@@ -41,6 +41,7 @@ > import org.eclipse.mat.snapshot.model.IObject; > import org.eclipse.mat.snapshot.query.IHeapObjectArgument; > import org.eclipse.mat.ui.Messages; >+import org.eclipse.mat.ui.accessibility.AccessibleCompositeAdapter; > import org.eclipse.mat.ui.internal.query.arguments.LinkEditor.Mode; > import org.eclipse.mat.ui.internal.query.arguments.TextEditor.DecoratorType; > import org.eclipse.mat.util.MessageUtil; >@@ -110,6 +111,7 @@ > table.setFont(parentFont); > table.setLinesVisible(true); > table.setHeaderVisible(true); >+ AccessibleCompositeAdapter.access(table); > > TableColumn column = new TableColumn(table, SWT.NONE); > column.setText(ARGUMENT); >Index: src/org/eclipse/mat/ui/internal/acquire/ProviderConfigurationDialog.java >=================================================================== >--- src/org/eclipse/mat/ui/internal/acquire/ProviderConfigurationDialog.java (revision 1101) >+++ src/org/eclipse/mat/ui/internal/acquire/ProviderConfigurationDialog.java (working copy) >@@ -28,6 +28,7 @@ > import org.eclipse.mat.query.registry.ArgumentFactory; > import org.eclipse.mat.snapshot.acquire.IHeapDumpProvider; > import org.eclipse.mat.ui.Messages; >+import org.eclipse.mat.ui.accessibility.AccessibleCompositeAdapter; > import org.eclipse.mat.ui.internal.browser.QueryContextHelp; > import org.eclipse.mat.util.IProgressListener; > import org.eclipse.mat.util.MessageUtil; >@@ -259,6 +260,7 @@ > > availableProvidersTable.setHeaderVisible(true); > availableProvidersTable.setLinesVisible(true); >+ AccessibleCompositeAdapter.access(availableProvidersTable); > > Collection<HeapDumpProviderDescriptor> providers = HeapDumpProviderRegistry.instance().getHeapDumpProviders(); > for (HeapDumpProviderDescriptor heapDumpProviderDescriptor : providers) >Index: src/org/eclipse/mat/ui/internal/viewer/RefinedTableViewer.java >=================================================================== >--- src/org/eclipse/mat/ui/internal/viewer/RefinedTableViewer.java (revision 1101) >+++ src/org/eclipse/mat/ui/internal/viewer/RefinedTableViewer.java (working copy) >@@ -18,6 +18,7 @@ > import org.eclipse.mat.query.refined.RefinedTable; > import org.eclipse.mat.query.refined.TotalsRow; > import org.eclipse.mat.query.registry.QueryResult; >+import org.eclipse.mat.ui.accessibility.AccessibleCompositeAdapter; > import org.eclipse.mat.ui.editor.AbstractEditorPane; > import org.eclipse.mat.ui.editor.MultiPaneEditor; > import org.eclipse.swt.SWT; >@@ -176,6 +177,7 @@ > table = new Table(parent, SWT.VIRTUAL | SWT.FULL_SELECTION | SWT.MULTI); > table.setHeaderVisible(true); > table.setLinesVisible(true); >+ AccessibleCompositeAdapter.access(table); > > table.addListener(SWT.SetData, new Listener() > { >Index: src/org/eclipse/mat/ui/internal/viewer/RefinedTreeViewer.java >=================================================================== >--- src/org/eclipse/mat/ui/internal/viewer/RefinedTreeViewer.java (revision 1101) >+++ src/org/eclipse/mat/ui/internal/viewer/RefinedTreeViewer.java (working copy) >@@ -26,6 +26,7 @@ > import org.eclipse.mat.query.refined.TotalsRow; > import org.eclipse.mat.query.registry.QueryResult; > import org.eclipse.mat.ui.Messages; >+import org.eclipse.mat.ui.accessibility.AccessibleCompositeAdapter; > import org.eclipse.mat.ui.editor.AbstractEditorPane; > import org.eclipse.mat.ui.editor.AbstractPaneJob; > import org.eclipse.mat.ui.editor.MultiPaneEditor; >@@ -549,6 +550,7 @@ > tree = new Tree(parent, SWT.FULL_SELECTION | SWT.MULTI); > tree.setHeaderVisible(true); > tree.setLinesVisible(true); >+ AccessibleCompositeAdapter.access(tree); > > return tree; > } >Index: src/org/eclipse/mat/ui/internal/views/NavigatorViewPage.java >=================================================================== >--- src/org/eclipse/mat/ui/internal/views/NavigatorViewPage.java (revision 1101) >+++ src/org/eclipse/mat/ui/internal/views/NavigatorViewPage.java (working copy) >@@ -38,6 +38,7 @@ > import org.eclipse.mat.ui.Messages; > import org.eclipse.mat.ui.QueryExecution; > import org.eclipse.mat.ui.MemoryAnalyserPlugin.ISharedImages; >+import org.eclipse.mat.ui.accessibility.AccessibleCompositeAdapter; > import org.eclipse.mat.ui.compare.CompareBasketView; > import org.eclipse.mat.ui.editor.AbstractEditorPane; > import org.eclipse.mat.ui.editor.CompositeHeapEditorPane; >@@ -154,6 +155,7 @@ > { > treeViewer = new TreeViewer(parent); > createContextMenu(treeViewer.getTree()); >+ AccessibleCompositeAdapter.access(treeViewer.getTree()); > > treeViewer.setContentProvider(new NavigatorContentProvider()); > treeViewer.setLabelProvider(new NavigatorLabelProvider()); >Index: src/org/eclipse/mat/ui/internal/views/SnapshotHistoryView.java >=================================================================== >--- src/org/eclipse/mat/ui/internal/views/SnapshotHistoryView.java (revision 1101) >+++ src/org/eclipse/mat/ui/internal/views/SnapshotHistoryView.java (working copy) >@@ -31,6 +31,7 @@ > import org.eclipse.mat.ui.SnapshotHistoryService; > import org.eclipse.mat.ui.MemoryAnalyserPlugin.ISharedImages; > import org.eclipse.mat.ui.SnapshotHistoryService.Entry; >+import org.eclipse.mat.ui.accessibility.AccessibleCompositeAdapter; > import org.eclipse.mat.ui.editor.PathEditorInput; > import org.eclipse.mat.ui.snapshot.views.SnapshotOutlinePage; > import org.eclipse.mat.ui.util.ErrorHelper; >@@ -196,6 +197,7 @@ > tableColumn.setText(Messages.SnapshotHistoryView_RecentlyUsedFiles); > tableColumn.setWidth(400); > table.setHeaderVisible(true); >+ AccessibleCompositeAdapter.access(table); > > table.addMouseListener(new MouseAdapter() > { >Index: src/org/eclipse/mat/ui/compare/CompareBasketView.java >=================================================================== >--- src/org/eclipse/mat/ui/compare/CompareBasketView.java (revision 1101) >+++ src/org/eclipse/mat/ui/compare/CompareBasketView.java (working copy) >@@ -43,6 +43,7 @@ > import org.eclipse.mat.ui.MemoryAnalyserPlugin; > import org.eclipse.mat.ui.Messages; > import org.eclipse.mat.ui.QueryExecution; >+import org.eclipse.mat.ui.accessibility.AccessibleCompositeAdapter; > import org.eclipse.mat.ui.actions.QueryDropDownMenuAction; > import org.eclipse.mat.ui.editor.AbstractEditorPane; > import org.eclipse.mat.ui.editor.MultiPaneEditor; >@@ -97,6 +98,7 @@ > { > tableViewer = new TableViewer(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL | SWT.FULL_SELECTION); > this.table = tableViewer.getTable(); >+ AccessibleCompositeAdapter.access(table); > > TableViewerColumn column = new TableViewerColumn(tableViewer, SWT.LEFT); > TableColumn tableColumn = column.getColumn(); >Index: src/org/eclipse/mat/ui/MemoryAnalyserPlugin.java >=================================================================== >--- src/org/eclipse/mat/ui/MemoryAnalyserPlugin.java (revision 1101) >+++ src/org/eclipse/mat/ui/MemoryAnalyserPlugin.java (working copy) >@@ -1,5 +1,5 @@ > /******************************************************************************* >- * Copyright (c) 2008, 2010 SAP AG and others. >+ * Copyright (c) 2008, 2011 SAP AG 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 >@@ -11,11 +11,18 @@ > *******************************************************************************/ > package org.eclipse.mat.ui; > >+import java.io.File; >+import java.io.FileNotFoundException; >+import java.io.FileOutputStream; >+import java.io.PrintStream; > import java.net.URI; > import java.net.URISyntaxException; > import java.net.URL; >+import java.util.ArrayList; > import java.util.HashMap; > import java.util.Map; >+import java.util.Map.Entry; >+import java.util.TreeMap; > import java.util.logging.Logger; > > import org.eclipse.core.runtime.IStatus; >@@ -99,7 +106,7 @@ > String CLOSE_BRANCH = "icons/close_branch.gif"; //$NON-NLS-1$ > > String PINNED = "icons/pinned.gif"; //$NON-NLS-1$ >- >+ > String MOVE_UP = "icons/move_up.gif"; //$NON-NLS-1$ > String MOVE_DOWN = "icons/move_down.gif"; //$NON-NLS-1$ > String REMOVE = "icons/remove.gif"; //$NON-NLS-1$ >@@ -116,9 +123,13 @@ > private ErrorLogHandler errorLogHandler; > private boolean useParentHandlers; > >+ // Mappings to permit textual descriptions of Images to be recovered from >+ // Images. >+ private Map<Image, String> imageTextMap = new HashMap<Image, String>(20); >+ private Map<ImageDescriptor, String> descriptorTextMap = new HashMap<ImageDescriptor, String>(20); >+ > public MemoryAnalyserPlugin() >- { >- } >+ {} > > @Override > public void start(BundleContext context) throws Exception >@@ -146,6 +157,9 @@ > for (Image image : imageCache.values()) > image.dispose(); > imageCache.clear(); >+ // Clear mappings from Image/Descriptor to descriptive text. >+ imageTextMap.clear(); >+ descriptorTextMap.clear(); > > logger.removeHandler(errorLogHandler); > logger.setUseParentHandlers(useParentHandlers); >@@ -166,7 +180,8 @@ > > public static ImageDescriptor getImageDescriptor(String path) > { >- return AbstractUIPlugin.imageDescriptorFromPlugin(PLUGIN_ID, path); >+ // Use singleton instance so that ImageDescriptor can be mapped to text. >+ return MemoryAnalyserPlugin.getDefault().getPluginImageDescriptor(path); > } > > public static Image getImage(String name) >@@ -174,6 +189,19 @@ > return MemoryAnalyserPlugin.getDefault().getImage(getImageDescriptor(name)); > } > >+ private ImageDescriptor getPluginImageDescriptor(String path) >+ { >+ ImageDescriptor descriptor = AbstractUIPlugin.imageDescriptorFromPlugin(PLUGIN_ID, path); >+ if (descriptor != null) >+ { // Add map entry for new descriptor to appropriate text. >+ // This should not result in a memory leak, assuming that two >+ // equivalent ImageDescriptors match under equals(). >+ // This is already assumed in the usage of imageCache. >+ descriptorTextMap.put(descriptor, getIconString(path)); >+ } >+ return descriptor; >+ } >+ > public Image getImage(ImageDescriptor descriptor) > { > Image image = imageCache.get(descriptor); >@@ -181,6 +209,9 @@ > { > image = descriptor.createImage(); > imageCache.put(descriptor, image); >+ // Map new Image to descriptive text. >+ // Should not cause memory leak as this must be a new descriptor. >+ imageTextMap.put(image, descriptorTextMap.get(descriptor)); > } > return image; > } >@@ -189,9 +220,12 @@ > { > // Use URI for maps to avoid blocking equals operation > URI pathKey; >- try { >+ try >+ { > pathKey = path.toURI(); >- } catch (URISyntaxException e) { >+ } >+ catch (URISyntaxException e) >+ { > // Will cause a missing image to be used instead > pathKey = null; > } >@@ -200,6 +234,10 @@ > { > descriptor = ImageDescriptor.createFromURL(path); > imagePathCache.put(pathKey, descriptor); >+ // Map new descriptor to descriptive text for the Image. >+ // Should not cause a memory leak as this is a new descriptor, >+ // and equivalent descriptors should overwrite existing entries. >+ descriptorTextMap.put(descriptor, getIconString(path)); > } > > return descriptor; >@@ -222,6 +260,110 @@ > return imageDescriptor == null ? null : getImage(imageDescriptor); > } > >+ /** >+ * @param url >+ * URL of image file for which a description is required. >+ * @return String with meaningful description of image given by input url. >+ */ >+ private String getIconString(URL url) >+ { >+ return getIconString(url.getPath()); // Delegate lookup based on path >+ // element of URL. >+ } >+ >+ /** >+ * @param path >+ * String representing the path to an image file for which a >+ * description is needed. >+ * @return String with meaningful description of image located at input >+ * path. NLS enabled as the string is obtained from a properties >+ * file. >+ */ >+ private String getIconString(String path) >+ { >+ // Construct system independent string representing path below "icons" >+ // This is then used to map to a NLS enabled textual description of the >+ // image. >+ File imageFile = new File(path); // Full path >+ String[] iconPath = parseIconPath(imageFile); // Split into elements >+ String iconKey = buildIconKey(iconPath); // Construct key for property >+ String iconLabel = IconLabels.getString(iconKey); // Obtain NLS value >+ return iconLabel; >+ } >+ >+ /** >+ * @param imageFile >+ * File representing the path to the image. This is converted >+ * into a String[] by splitting the path into elements below the >+ * /icons directory and stripping off the suffix. Returns null if >+ * the file is not below an /icons directory. >+ * @return String[] representing the path split into elements as above. >+ */ >+ private static String[] parseIconPath(File imageFile) >+ { >+ String[] iconPath = null; // Initial and default value to return. >+ ArrayList<String> pathList = new ArrayList<String>(); // Accumulator >+ pathList.add(imageFile.getName().split("\\.")[0]); // Strip off file >+ // suffix. >+ // Iterate backwards up the path, inserting the directory names at the >+ // front of the ArrayList. >+ // This results in a sequence matching the original order of the path. >+ // Do not include the common parent directory "/icons" or ancestors. >+ while (imageFile != null) >+ { // iterate up the path >+ imageFile = imageFile.getParentFile(); >+ if (imageFile != null) // There was a parent to include. >+ { >+ String fileName = imageFile.getName(); >+ if (fileName.equals("icons")) // Iteration complete. >+ { // Convert ArrayList to array for return. >+ iconPath = pathList.toArray(new String[0]); >+ imageFile = null; // terminate loop >+ } >+ else >+ { // More to do - prepend the name of parent to sequence. >+ pathList.add(0, fileName); // add parent to front of list >+ } >+ } >+ } >+ return iconPath; // Return parsed path, or null if unexpected error. >+ } >+ >+ /** >+ * @param iconPath >+ * String[] representing path to icon file below /icons >+ * @return String A mangled version of the path with path separators >+ * replaced with '-' to use as a key into the properties file >+ * containing the textual descriptions of the icons. This utility is >+ * used offline to build the properties file, and at runtime to look >+ * up the icon labels from the NLS properties file(s). >+ */ >+ private static String buildIconKey(String[] iconPath) >+ { >+ // Initialize key with common prefix from IconLabels class. >+ StringBuffer propertyBuf = new StringBuffer(IconLabels.ICON_KEY_PREFIX); >+ // Iterate through iconPath appending each element after '-' >+ for (String pathStr : iconPath) >+ { >+ propertyBuf.append('-'); >+ propertyBuf.append(pathStr); >+ } >+ return propertyBuf.toString(); // Return constructed key. >+ } >+ >+ /** >+ * @param image >+ * The Image for which descriptive text is to be retrieved. >+ * @return Descriptive text for the Image object, retrieved from >+ * imageTextMap, or text indicating "unknown image" if not found. >+ */ >+ public String getImageText(Image image) >+ { >+ String text = imageTextMap.get(image); // May be null >+ // Return default string if image not in map. >+ return (text == null) ? IconLabels.getString(IconLabels.UNKNOWN_ICON_KEY) : text; >+ } >+ > public IExtensionTracker getExtensionTracker() > { > return tracker; >@@ -245,4 +387,213 @@ > { > log(new Status(IStatus.ERROR, PLUGIN_ID, message, e)); > } >+ >+ // /////////////////////////////////////////////////////////////////// >+ // Main program and associated methods (all offline code) >+ // to generate icon label properties from icon file names. >+ // Not used in MAT runtime environment. >+ // Offline code to generate English labels for icons. >+ // The standard required for error handling robustness in this code is >+ // lower than would be expected for MAT runtime code, as it is run only >+ // as an offline generation utility (by MAT developers only, not by users). >+ // /////////////////////////////////////////////////////////////////// >+ >+ /** >+ * @param args >+ * Input arguments are ignored. This Java program generates a >+ * properties file "iconlabels.properties" automatically, based >+ * on the content of the MAT icons directories. The locations of >+ * the /icons directories are hardcoded to be those under >+ * org.eclipse.mat.api and org.eclipse.mat.ui, relative to the >+ * current working directory which is assumed to be a project in >+ * the workspace. This is the case if this program is >+ * "Run as Java Application" within Eclipse, using the default >+ * working directory org.eclipse.mat.ui. The output is written to >+ * "iconlabels.properties" in the current working directory, >+ * which can then be copied to the required location for the >+ * properties file, org.eclipse.mat.ui/src/org/eclipse/mat/ui/. >+ * Error handling is coarse-grained: any Exception is caught and >+ * details are printed to System.out. Some other diagnostics are >+ * written to System.out if errors occur. >+ */ >+ public static void main(String[] args) >+ { >+ /* >+ * Note that the file output uses \r\n as the line separator, as this is >+ * required by the IBM NLS translation tools. This corresponds to 0x0D0A >+ * in ASCII/UTF-8 encoding. Hence explicit line separators of \r\n are >+ * used throughout the generator code. >+ */ >+ // File for output properties: >+ final String propsFilename = "iconlabels.properties"; >+ // Header string required for translation tooling. >+ final String nlsHeaders = "# NLS_MESSAGEFORMAT_NONE\r\n" + "# NLS_ENCODING=UNICODE\r\n" + "# \r\n"; >+ // Header comment for generated properties file, referring back to this >+ // program. >+ final String autoComment = "# This file is automatically generated by org.eclipse.mat.ui.MemoryAnalyserPlugin.main().\r\n" >+ + "# Refer to the documentation/comments for this method for usage instructions.\r\n" >+ + "# \r\n" >+ + "# Any manual modifications to this file will need to be reapplied if the file is regenerated.\r\n" >+ + "# Therefore it is preferable if such modifications are kept to a minimum, or preferably\r\n" >+ + "# achieved by amending the label generation code in MemoryAnalyserPlugin.buildIconLabel().\r\n" >+ + "# \r\n"; >+ // String to include special property to denote the "unknown icon" >+ // value. >+ final String unknownIconProperty = "# Icon label property to be used for an unknown icon:\r\n" >+ + IconLabels.UNKNOWN_ICON_KEY + "=" + buildIconLabel(null) + "\r\n"; >+ // String to indicate start of auto-generated label properties. >+ final String autoIconsComment = "# Automatically generated icon label properties:"; >+ final String[] iconDirs = { // UI draws icons from several locations >+ // Assume the following two top-level icons directories relative to >+ // current directoy. >+ "..\\org.eclipse.mat.api\\META-INF\\icons", "..\\org.eclipse.mat.ui\\icons" }; >+ try >+ // Trap any Exceptions at the outermost level. >+ { >+ // Use a sorted map for the properties so that the ordering is >+ // reproducible. >+ Map<String, String> iconMap = new TreeMap<String, String>(); >+ for (String iconDir : iconDirs) // For each /icons directory >+ // (currently 2). >+ { >+ File iconDirFile = new File(iconDir); >+ if (iconDirFile.isDirectory()) // Check input is valid directory >+ { // Generate properties for the directory and add to map. >+ generateIconProps(iconDirFile, iconMap); >+ } >+ else >+ { // Error case - report to user. >+ System.out.println("Input is not a directory: " + iconDir); >+ } >+ >+ } >+ // Now write out iconlabels.properties >+ File iconLabelsFile = new File(propsFilename); >+ PrintStream iconLabelsStream = null; >+ iconLabelsStream = new PrintStream(new FileOutputStream(iconLabelsFile)); >+ // Print NLS headers required for translation >+ // Use printPropertyLine() to insert \r\n separator. >+ printPropertyLine(iconLabelsStream, nlsHeaders); >+ // Print header comment referring to this generator code. >+ printPropertyLine(iconLabelsStream, autoComment); >+ // Print special label to be used for unknown icons. >+ printPropertyLine(iconLabelsStream, unknownIconProperty); >+ // Print special label to be used for unknown icons. >+ printPropertyLine(iconLabelsStream, autoIconsComment); >+ // Print out iconMap entries, in collation sequence for >+ // reproducibility. >+ for (Entry<String, String> mapEntry : iconMap.entrySet()) >+ { >+ iconLabelsStream.print(mapEntry.getKey()); >+ iconLabelsStream.print('='); >+ printPropertyLine(iconLabelsStream, mapEntry.getValue()); >+ } >+ iconLabelsStream.close(); >+ // Print completion message to console >+ System.out.println("Icon label properties written to file: " + iconLabelsFile.getAbsolutePath()); >+ } >+ catch (Exception e) // Catch all exceptions and print details to >+ // System.out >+ { >+ System.out.println(e.toString()); >+ e.printStackTrace(System.out); >+ } >+ } >+ >+ /** >+ * @param stream >+ * PrintStream to print line to. >+ * @param line >+ * String to append to PrintStream. Writes line to stream (just >+ * like println()) but using "\r\n" as line terminator to satisfy >+ * requirements of IBM translation tools. >+ */ >+ private static void printPropertyLine(PrintStream stream, String line) >+ { >+ stream.print(line); >+ stream.print("\r\n"); // Use MS-DOS line termination (0D0A) for >+ } >+ >+ /** >+ * @param iconDir >+ * File representing a directory to search for icon files and to >+ * add the generated key/value pairs to iconMap. >+ * @param iconMap >+ * Map to add the generated key/value pairs for the icons. This >+ * should be a sorted Map to ensure reproducible ordering of >+ * output. Recursively invoked method to write out generated >+ * labels for icons in the form of a properties file. The >+ * recursion excludes hidden files & directories >+ */ >+ private static void generateIconProps(File iconDir, Map<String, String> iconMap) >+ { // precondition: iconDir is a directory. >+ File[] fileList = iconDir.listFiles(); // Should not be null, may be >+ // empty. >+ for (File file : fileList) // Iterate over directory contents. >+ { >+ if (!file.isHidden()) >+ { // Exclude hidden files eg .svn directories >+ if (file.isDirectory()) >+ { // Directory, so recurse into child directory. >+ generateIconProps(file, iconMap); >+ } >+ else >+ { // File, so add key/value pair to Map. >+ String[] iconPath = parseIconPath(file); >+ String key = buildIconKey(iconPath); >+ String label = buildIconLabel(iconPath); >+ iconMap.put(key, label); // Duplicate key will overwrite >+ } >+ } // if() >+ } >+ } >+ >+ /** >+ * @param iconPath >+ * path of icon below "/icons", without file qualifier(s), parsed >+ * into String[] by >+ * @return We simply return a line representing a textual description for >+ * the icon, based on it's file location & name. This automated >+ * process can be adjusted to produce any desired result, provided >+ * the resulting line is a valid Java property value. Performance is >+ * not important as this is non-runtime code. It's more important >+ * that the results should be readily tailorable. >+ */ >+ private static String buildIconLabel(String[] iconPath) >+ { >+ // Input is path of icon below "/icons", without file qualifier(s). >+ if (iconPath == null) // Invalid path, icon may not exist. >+ return "unknown icon"; // Special case label. >+ StringBuffer labelBuf = new StringBuffer(); // Initially empty >+ // Split base file name of icon into tokens delimited by '_' >+ String[] iconName = iconPath[iconPath.length - 1].split("_"); >+ for (String nameElem : iconName) >+ { // For each component token, perform required tailoring. >+ // Expand common abbreviations >+ if (nameElem.equals("obj")) >+ nameElem = "object"; >+ if (nameElem.equals("frgmt")) >+ nameElem = "fragment"; >+ if (nameElem.equals("frgmts")) >+ nameElem = "fragments"; >+ if (nameElem.equals("attr")) >+ nameElem = "attribute"; >+ if (nameElem.equals("ext")) >+ nameElem = "extension"; >+ if (nameElem.equals("mpaths")) >+ nameElem = "merge paths"; >+ // Add to buffer >+ labelBuf.append(nameElem); >+ labelBuf.append(' '); // Add space between elements >+ } >+ // Iterate backwards up path, adding parent directory names to text. >+ for (int ipath = iconPath.length - 2; ipath >= 1; ipath--) >+ { // omit top-level directory if there is one (index 0 not included). >+ labelBuf.append(iconPath[ipath]); >+ labelBuf.append(' '); // Appends trailing blank which is OK for >+ // properties >+ } >+ return labelBuf.toString(); // Convert to String and return. >+ } >+ > } >Index: src/org/eclipse/mat/ui/accessibility/AccessibleCompositeAdapter.java >=================================================================== >--- src/org/eclipse/mat/ui/accessibility/AccessibleCompositeAdapter.java (revision 0) >+++ src/org/eclipse/mat/ui/accessibility/AccessibleCompositeAdapter.java (revision 0) >@@ -0,0 +1,216 @@ >+/******************************************************************************* >+ * Copyright (c) 2011 IBM Corporation. >+ * 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: >+ * IBM Corporation - initial implementation >+ *******************************************************************************/ >+ >+package org.eclipse.mat.ui.accessibility; >+ >+import org.eclipse.mat.ui.MemoryAnalyserPlugin; >+import org.eclipse.swt.accessibility.ACC; >+import org.eclipse.swt.accessibility.AccessibleAdapter; >+import org.eclipse.swt.accessibility.AccessibleControlAdapter; >+import org.eclipse.swt.accessibility.AccessibleControlEvent; >+import org.eclipse.swt.accessibility.AccessibleEvent; >+import org.eclipse.swt.graphics.Image; >+import org.eclipse.swt.widgets.Composite; >+import org.eclipse.swt.widgets.Item; >+import org.eclipse.swt.widgets.Table; >+import org.eclipse.swt.widgets.TableItem; >+import org.eclipse.swt.widgets.Tree; >+import org.eclipse.swt.widgets.TreeItem; >+ >+/** >+ * AccessibleCompositeAdapter Accessibility utility class provides a single >+ * encapsulated implementation of accessibility enhancements for Table & Tree >+ * Controls within MAT. The implementation is essentially the same for both >+ * types of view, adding an Accessible Listener to cause a specially constructed >+ * name for each item to be passed to the accessibility client (Screen Reader). >+ * >+ * @author Jonathan Lawrence >+ */ >+public class AccessibleCompositeAdapter >+{ >+ >+ // Constants for String construction. >+ private static final char space = ' '; >+ >+ // Public methods provide interface ensuring only Table or Tree are used. >+ /** >+ * @param table >+ * The Table to decorate with Accessible. >+ */ >+ public static void access(Table table) >+ { >+ access(table, ACC.ROLE_TABLE); // Delegate to generic private method. >+ } >+ >+ /** >+ * @param tree >+ * The Tree to decorate with Accessible. >+ */ >+ public static void access(Tree tree) >+ { >+ access(tree, ACC.ROLE_TREE); // Delegate to generic private method. >+ } >+ >+ /** >+ * @param composite >+ * The Composite (Table/Tree) to add Accessibility >+ * @param role >+ * The ACC.ROLE constant representing the type of Composite. >+ */ >+ private static void access(final Composite composite, final int role) >+ { >+ // Add addAccessibleListener to override getName. >+ composite.getAccessible().addAccessibleListener(new AccessibleAdapter() >+ { >+ >+ @Override >+ public void getName(AccessibleEvent e) >+ { >+ if (e.childID == ACC.CHILDID_SELF) >+ { >+ // TODO - provide a suitable name for the Tree/Table. >+ } >+ else >+ { // Name is required for a child of the Composite. >+ >+ // Get the item... >+ Item item = null; >+ try >+ { >+ // Defensive coding. For Tree Controls, JAWS 12 >+ // sometimes >+ // calls this method with invalid childIDs. >+ int maxchild = getItemCount(composite, role); >+ if (e.childID >= 0 && e.childID < maxchild) >+ { // Valid range >+ // Get Item >+ item = getItem(composite, role, e.childID); >+ } >+ // Otherwise use first selected item if any. >+ else >+ { >+ item = getSelection(composite, role)[0]; >+ } >+ } >+ catch (IndexOutOfBoundsException ie) >+ { // Do nothing >+ // item will be null, no name will be returned in e. >+ >+ } // catch() >+ >+ // Construct a row of readable text for the Table/TreeItem >+ if (item != null) // Valid item >+ { >+ int ncol = getColumnCount(composite, role); >+ int[] colorder = getColumnOrder(composite, role); >+ StringBuffer rowbuf = new StringBuffer(); >+ Item column = null; >+ Image image = null; >+ for (int icol = 0; icol < ncol; icol++) // For each >+ // column >+ { >+ int jcol = colorder[icol]; // The index of the >+ // column when created. >+ image = getImage(item, role, jcol); // Get image if >+ // any >+ if (image != null) // Image exists in this column >+ { // Append the descriptive text for this image >+ rowbuf.append(MemoryAnalyserPlugin.getDefault().getImageText(image)); >+ rowbuf.append(space); >+ } >+ String cellText = getText(item, role, jcol); >+ // if cell has any non-white space content... >+ if (!cellText.trim().equals("")) >+ { // Only add text if the cell is non-empty >+ // Get relevant Column >+ column = getColumn(composite, role, jcol); >+ // Append column header text >+ rowbuf.append(column.getText()); >+ rowbuf.append(space); >+ // Append column cell content >+ rowbuf.append(cellText); >+ rowbuf.append(space); >+ } // if() >+ } >+ e.result = rowbuf.toString(); >+ } // if() >+ } // if() >+ } // getName() >+ >+ }); >+ >+ // Experimentation with JAWS 12 shows that the following is also >+ // required to ensure >+ // that JAWS will read out the name returned for the Item. >+ composite.getAccessible().addAccessibleControlListener(new AccessibleControlAdapter() >+ { >+ @Override >+ public void getRole(AccessibleControlEvent e) >+ { >+ if (e.childID == ACC.CHILDID_SELF) >+ { >+ e.detail = role; // The ACC.ROLE constant for the Control. >+ } >+ else >+ { >+ e.detail = ACC.ROLE_TEXT; // Return TEXT for an Item. >+ } // if() >+ } // getRole() >+ }); >+ >+ } >+ >+ // ////////////////////////////////////////////////////////////// >+ // Utility methods to map inquiry methods onto the Control-type >+ // specific variants for Table or Tree, as required. >+ // ////////////////////////////////////////////////////////////// >+ >+ private static Item getColumn(Composite composite, int role, int index) >+ { >+ return (role == ACC.ROLE_TABLE) ? ((Table) composite).getColumn(index) : ((Tree) composite).getColumn(index); >+ } >+ >+ private static int getColumnCount(Composite composite, int role) >+ { >+ return (role == ACC.ROLE_TABLE) ? ((Table) composite).getColumnCount() : ((Tree) composite).getColumnCount(); >+ } >+ >+ private static int[] getColumnOrder(Composite composite, int role) >+ { >+ return (role == ACC.ROLE_TABLE) ? ((Table) composite).getColumnOrder() : ((Tree) composite).getColumnOrder(); >+ } >+ >+ private static Item getItem(Composite composite, int role, int index) >+ { >+ return (role == ACC.ROLE_TABLE) ? ((Table) composite).getItem(index) : ((Tree) composite).getItem(index); >+ } >+ >+ private static Item[] getSelection(Composite composite, int role) >+ { >+ return (role == ACC.ROLE_TABLE) ? ((Table) composite).getSelection() : ((Tree) composite).getSelection(); >+ } >+ >+ private static int getItemCount(Composite composite, int role) >+ { >+ return (role == ACC.ROLE_TABLE) ? ((Table) composite).getItemCount() : ((Tree) composite).getItemCount(); >+ } >+ >+ private static Image getImage(Item item, int role, int index) >+ { >+ return (role == ACC.ROLE_TABLE) ? ((TableItem) item).getImage(index) : ((TreeItem) item).getImage(index); >+ } >+ >+ private static String getText(Item item, int role, int index) >+ { >+ return (role == ACC.ROLE_TABLE) ? ((TableItem) item).getText(index) : ((TreeItem) item).getText(index); >+ } >+ >+} >Index: src/org/eclipse/mat/ui/IconLabels.java >=================================================================== >--- src/org/eclipse/mat/ui/IconLabels.java (revision 0) >+++ src/org/eclipse/mat/ui/IconLabels.java (revision 0) >@@ -0,0 +1,39 @@ >+/******************************************************************************* >+ * Copyright (c) 2011 IBM Corporation. >+ * 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: >+ * IBM Corporation - initial implementation >+ *******************************************************************************/ >+ >+package org.eclipse.mat.ui; >+ >+import java.util.MissingResourceException; >+import java.util.ResourceBundle; >+ >+public class IconLabels >+{ >+ public static final String ICON_KEY_PREFIX = "IconLabel"; //$NON-NLS-1$ >+ public static final String UNKNOWN_ICON_KEY = ICON_KEY_PREFIX + "Unknown"; //$NON-NLS-1$ >+ >+ private static final String BUNDLE_NAME = "org.eclipse.mat.ui.iconlabels"; //$NON-NLS-1$ >+ private static final ResourceBundle RESOURCE_BUNDLE = ResourceBundle.getBundle(BUNDLE_NAME); >+ >+ private IconLabels() >+ {} >+ >+ public static String getString(String key) >+ { >+ try >+ { >+ return RESOURCE_BUNDLE.getString(key); >+ } >+ catch (MissingResourceException e) >+ { >+ return RESOURCE_BUNDLE.getString(UNKNOWN_ICON_KEY); // Should exist. >+ } >+ } >+} >Index: src/org/eclipse/mat/ui/snapshot/actions/OpenIconAssistAction.java >=================================================================== >--- src/org/eclipse/mat/ui/snapshot/actions/OpenIconAssistAction.java (revision 1101) >+++ src/org/eclipse/mat/ui/snapshot/actions/OpenIconAssistAction.java (working copy) >@@ -37,6 +37,7 @@ > import org.eclipse.mat.query.registry.QueryRegistry; > import org.eclipse.mat.ui.MemoryAnalyserPlugin; > import org.eclipse.mat.ui.Messages; >+import org.eclipse.mat.ui.accessibility.AccessibleCompositeAdapter; > import org.eclipse.mat.ui.snapshot.ImageHelper; > import org.eclipse.swt.SWT; > import org.eclipse.swt.events.ControlEvent; >@@ -284,6 +285,7 @@ > shell = new Shell(parent, checkStyle(style)); > TableViewer viewer = new TableViewer(shell, SWT.WRAP | SWT.V_SCROLL | SWT.H_SCROLL); > table = viewer.getTable(); >+ AccessibleCompositeAdapter.access(table); > TableColumn tc1 = new TableColumn(table, SWT.CENTER); > TableColumn tc2 = new TableColumn(table, SWT.LEFT); > tc1.setWidth(25); >Index: src/org/eclipse/mat/ui/snapshot/views/SnapshotOutlinePage.java >=================================================================== >--- src/org/eclipse/mat/ui/snapshot/views/SnapshotOutlinePage.java (revision 1101) >+++ src/org/eclipse/mat/ui/snapshot/views/SnapshotOutlinePage.java (working copy) >@@ -28,6 +28,7 @@ > import org.eclipse.jface.viewers.Viewer; > import org.eclipse.mat.snapshot.ISnapshot; > import org.eclipse.mat.snapshot.SnapshotInfo; >+import org.eclipse.mat.ui.accessibility.AccessibleCompositeAdapter; > import org.eclipse.mat.ui.snapshot.editor.ISnapshotEditorInput; > import org.eclipse.mat.util.MessageUtil; > import org.eclipse.swt.SWT; >@@ -253,6 +254,8 @@ > > createColumns(); > >+ AccessibleCompositeAdapter.access(treeViewer.getTree()); >+ > treeViewer.getTree().setLinesVisible(true); > treeViewer.getTree().setHeaderVisible(true); > >Index: src/org/eclipse/mat/ui/snapshot/views/inspector/InspectorView.java >=================================================================== >--- src/org/eclipse/mat/ui/snapshot/views/inspector/InspectorView.java (revision 1101) >+++ src/org/eclipse/mat/ui/snapshot/views/inspector/InspectorView.java (working copy) >@@ -57,6 +57,7 @@ > import org.eclipse.mat.snapshot.model.IPrimitiveArray; > import org.eclipse.mat.ui.MemoryAnalyserPlugin; > import org.eclipse.mat.ui.Messages; >+import org.eclipse.mat.ui.accessibility.AccessibleCompositeAdapter; > import org.eclipse.mat.ui.accessibility.AccessibleToolbarAdapter; > import org.eclipse.mat.ui.snapshot.ImageHelper; > import org.eclipse.mat.ui.snapshot.editor.HeapEditor; >@@ -445,6 +446,7 @@ > topTableViewer = new TableViewer(composite, SWT.FULL_SELECTION | SWT.MULTI); > > Table table = topTableViewer.getTable(); >+ AccessibleCompositeAdapter.access(table); > TableColumnLayout columnLayout = new TableColumnLayout(); > composite.setLayout(columnLayout); > >@@ -572,6 +574,7 @@ > classHierarchyTree.setLabelProvider(new HierarchyLabelProvider(-1)); > > Tree tree = classHierarchyTree.getTree(); >+ AccessibleCompositeAdapter.access(tree); > TreeColumnLayout columnLayout = new TreeColumnLayout(); > composite.setLayout(columnLayout); > >@@ -590,6 +593,7 @@ > > final TableViewer viewer = new TableViewer(composite, SWT.H_SCROLL | SWT.V_SCROLL | SWT.FULL_SELECTION | SWT.MULTI); > Table table = viewer.getTable(); >+ AccessibleCompositeAdapter.access(table); > viewer.setContentProvider(new FieldsContentProvider()); > viewer.setLabelProvider(new FieldsLabelProvider(this, table.getFont())); > >
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Flags:
andrew_johnson
:
iplog+
Actions:
View
|
Diff
Attachments on
bug 341685
:
192401
| 193433