[572227] Add an option for headless text output without a zip
Option to use the new text renderer for UI export.
Add tree expansion to text renderer.
Change-Id: Ie6c11566c95675f1f1f421a87ec57a8eb9b8041b
Task-Url: https://bugs.eclipse.org/bugs/show_bug.cgi?id=572227
diff --git a/plugins/org.eclipse.mat.api/src/org/eclipse/mat/inspections/LeakHunterQuery.java b/plugins/org.eclipse.mat.api/src/org/eclipse/mat/inspections/LeakHunterQuery.java
index 7c288c2..3192829 100644
--- a/plugins/org.eclipse.mat.api/src/org/eclipse/mat/inspections/LeakHunterQuery.java
+++ b/plugins/org.eclipse.mat.api/src/org/eclipse/mat/inspections/LeakHunterQuery.java
@@ -1,10 +1,10 @@
/*******************************************************************************
- * Copyright (c) 2008, 2020 SAP AG, IBM Corporation and others.
+ * Copyright (c) 2008, 2021 SAP AG, IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
- * https://www.eclipse.org/legal/epl-2.0/
- *
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
@@ -255,7 +255,7 @@
{
overview.append("<p>"); //$NON-NLS-1$
overview.append(MessageUtil.format(Messages.LeakHunterQuery_Msg_Thread, //
- HTMLUtils.escapeText(suspect.getSuspect().getDisplayName()), //
+ HTMLUtils.escapeText(suspect.getSuspect().getDisplayName()), //
formatRetainedHeap(suspect.getSuspectRetained(), totalHeap)));
overview.append("</p>"); //$NON-NLS-1$
}
@@ -282,7 +282,7 @@
String classloaderName = getClassLoaderName(suspectClassloader, keywords);
overview.append(MessageUtil.format(Messages.LeakHunterQuery_Msg_Class, //
- HTMLUtils.escapeText(className), classloaderName, formatRetainedHeap(suspect.getSuspectRetained(), totalHeap)));
+ HTMLUtils.escapeText(className), classloaderName, formatRetainedHeap(suspect.getSuspectRetained(), totalHeap)));
}
else
{
@@ -297,7 +297,7 @@
String classloaderName = getClassLoaderName(suspectClassloader, keywords);
overview.append(MessageUtil.format(Messages.LeakHunterQuery_Msg_Instance, //
- HTMLUtils.escapeText(className), classloaderName, formatRetainedHeap(suspect.getSuspectRetained(), totalHeap)));
+ HTMLUtils.escapeText(className), classloaderName, formatRetainedHeap(suspect.getSuspectRetained(), totalHeap)));
/*
* if the class name matches the skip pattern, try to find the first
@@ -338,8 +338,8 @@
// involvedClassloaders.add(suspectClassloader);
objectsForTroubleTicketInfo.add(referrer);
String referrerClassloaderName = getClassLoaderName(referrerClassloader, keywords);
- overview.append(MessageUtil.format(Messages.LeakHunterQuery_Msg_ReferencedByInstance, HTMLUtils.escapeText(referrer
- .getDisplayName()), referrerClassloaderName));
+ overview.append(MessageUtil.format(Messages.LeakHunterQuery_Msg_ReferencedByInstance, HTMLUtils.escapeText(referrer
+ .getDisplayName()), referrerClassloaderName));
}
}
@@ -371,7 +371,7 @@
String classloaderName = getClassLoaderName(accPointClassloader, keywords);
- overview.append(MessageUtil.format(Messages.LeakHunterQuery_Msg_AccumulatedByLoadedBy, HTMLUtils.escapeText(clazz.getName()),
+ overview.append(MessageUtil.format(Messages.LeakHunterQuery_Msg_AccumulatedByLoadedBy, HTMLUtils.escapeText(clazz.getName()),
classloaderName, formatRetainedHeap(suspect.getAccumulationPoint().getRetainedHeapSize(), totalHeap)));
}
else
@@ -385,7 +385,7 @@
objectsForTroubleTicketInfo.add(accumulationObject);
String classloaderName = getClassLoaderName(accPointClassloader, keywords);
- overview.append(MessageUtil.format(Messages.LeakHunterQuery_Msg_AccumulatedByInstance, HTMLUtils.escapeText(className),
+ overview.append(MessageUtil.format(Messages.LeakHunterQuery_Msg_AccumulatedByInstance, HTMLUtils.escapeText(className),
classloaderName, formatRetainedHeap(suspect.getAccumulationPoint().getRetainedHeapSize(), totalHeap)));
}
}
@@ -508,7 +508,7 @@
String classloaderName = getClassLoaderName(classloader, keywords);
String numberOfInstances = numberFormatter.format(suspect.getSuspectInstances().length);
- builder.append(MessageUtil.format(Messages.LeakHunterQuery_Msg_InstancesOccupy, numberOfInstances, HTMLUtils.escapeText(className),
+ builder.append(MessageUtil.format(Messages.LeakHunterQuery_Msg_InstancesOccupy, numberOfInstances, HTMLUtils.escapeText(className),
classloaderName, formatRetainedHeap(suspect.getSuspectRetained(), totalHeap)));
int[] suspectInstances = suspect.getSuspectInstances();
@@ -527,13 +527,13 @@
builder.append("<ul>"); //$NON-NLS-1$
for (IObject inst : bigSuspectInstances)
{
- builder.append("<li>").append(HTMLUtils.escapeText(inst.getDisplayName())); //$NON-NLS-1$
+ builder.append("<li>").append(HTMLUtils.escapeText(inst.getDisplayName())); //$NON-NLS-1$
builder.append(" - ") //$NON-NLS-1$
.append(
MessageUtil.format(Messages.LeakHunterQuery_Msg_Bytes,
formatRetainedHeap(inst.getRetainedHeapSize(),
totalHeap)));
- builder.append("</li>"); //$NON-NLS-1$
+ builder.append("</li>"); //$NON-NLS-1$
}
builder.append("</ul>"); //$NON-NLS-1$
}
@@ -831,12 +831,12 @@
return name;
}
- /**
- * Get the name of the class loader.
- * @param classloader
- * @param keywords
- * @return The name with HTML escapes already applied.
- */
+ /**
+ * Get the name of the class loader.
+ * @param classloader
+ * @param keywords
+ * @return The name with HTML escapes already applied.
+ */
private String getClassLoaderName(IObject classloader, Set<String> keywords)
{
if (classloader.getObjectAddress() == 0)
@@ -850,7 +850,7 @@
{
keywords.add(classloaderName);
}
- return HTMLUtils.escapeText(classloaderName);
+ return HTMLUtils.escapeText(classloaderName);
}
}
@@ -948,7 +948,7 @@
{
builder.append("<b>").append(Messages.LeakHunterQuery_Keywords).append("</b><br>"); //$NON-NLS-1$ //$NON-NLS-2$
for (String s : keywords)
- builder.append(HTMLUtils.escapeText(s)).append("<br>"); //$NON-NLS-1$
+ builder.append(HTMLUtils.escapeText(s)).append("<br>"); //$NON-NLS-1$
}
private void appendTroubleTicketInformation(List<IObject> classloaders, StringBuilder builder)
@@ -960,12 +960,12 @@
if (!mapping.isEmpty())
{
- builder.append("<br><b>").append(HTMLUtils.escapeText(resolver.getTicketSystem())).append("</b><br>"); //$NON-NLS-1$ //$NON-NLS-2$
+ builder.append("<br><b>").append(HTMLUtils.escapeText(resolver.getTicketSystem())).append("</b><br>"); //$NON-NLS-1$ //$NON-NLS-2$
for (Map.Entry<String, String> entry : mapping.entrySet())
{
builder.append(
- MessageUtil.format(Messages.LeakHunterQuery_TicketForSuspect, HTMLUtils.escapeText(entry.getKey()), HTMLUtils.escapeText(entry
- .getValue()))).append("<br>"); //$NON-NLS-1$
+ MessageUtil.format(Messages.LeakHunterQuery_TicketForSuspect, HTMLUtils.escapeText(entry.getKey()), HTMLUtils.escapeText(entry
+ .getValue()))).append("<br>"); //$NON-NLS-1$
}
}
}
@@ -993,7 +993,7 @@
builder.append("<p>"); //$NON-NLS-1$
for (CompositeResult.Entry requestInfo : requestInfos.getResultEntries())
- builder.append(HTMLUtils.escapeText(requestInfo.getName())).append(" ").append( //$NON-NLS-1$
+ builder.append(HTMLUtils.escapeText(requestInfo.getName())).append(" ").append( //$NON-NLS-1$
textResult.linkTo(Messages.LeakHunterQuery_RequestDetails,
requestInfo.getResult())).append("<br>"); //$NON-NLS-1$
@@ -1090,14 +1090,26 @@
*/
public boolean isExpanded(Object row)
{
+ // Any thread should be expanded
if (rt.getElements().contains(row))
return true;
for (Object r2 : rt.getChildren(row))
{
- // if row is a stack frame row
+ // If row has a child which is a local
IContextObject co = rt.getContext(r2);
if (co != null && locals.contains(co.getObjectId()))
- { return true; }
+ {
+ /*
+ * It needs to be a stack frame row though to
+ * be expanded.
+ */
+ for (Object r3 : rt.getElements())
+ {
+ // Relies on ThreadOverviewQuery.ThreadStackFrameNode equals()
+ if (rt.getChildren(r3).contains(row))
+ return true;
+ }
+ }
}
return false;
}
diff --git a/plugins/org.eclipse.mat.api/src/org/eclipse/mat/inspections/threads/ThreadOverviewQuery.java b/plugins/org.eclipse.mat.api/src/org/eclipse/mat/inspections/threads/ThreadOverviewQuery.java
index edc1dab..1142b18 100644
--- a/plugins/org.eclipse.mat.api/src/org/eclipse/mat/inspections/threads/ThreadOverviewQuery.java
+++ b/plugins/org.eclipse.mat.api/src/org/eclipse/mat/inspections/threads/ThreadOverviewQuery.java
@@ -1,10 +1,10 @@
/*******************************************************************************
- * Copyright (c) 2008, 2020 SAP AG, IBM Corporation and others.
+ * Copyright (c) 2008, 2021 SAP AG, IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
- * https://www.eclipse.org/legal/epl-2.0/
- *
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
@@ -238,6 +238,28 @@
private static class ThreadStackFrameNode
{
+ @Override
+ public int hashCode()
+ {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + depth;
+ return result;
+ }
+ @Override
+ public boolean equals(Object obj)
+ {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ ThreadStackFrameNode other = (ThreadStackFrameNode) obj;
+ if (depth != other.depth)
+ return false;
+ return true;
+ }
private ThreadOverviewNode threadOverviewNode;
private IStackFrame stackFrame;
private int depth;
diff --git a/plugins/org.eclipse.mat.report/src/org/eclipse/mat/report/internal/CSVOutputter.java b/plugins/org.eclipse.mat.report/src/org/eclipse/mat/report/internal/CSVOutputter.java
index 3d0cfa2..3ce39c5 100644
--- a/plugins/org.eclipse.mat.report/src/org/eclipse/mat/report/internal/CSVOutputter.java
+++ b/plugins/org.eclipse.mat.report/src/org/eclipse/mat/report/internal/CSVOutputter.java
@@ -22,8 +22,6 @@
import org.eclipse.mat.query.IResultTable;
import org.eclipse.mat.query.IResultTree;
import org.eclipse.mat.query.refined.Filter;
-import org.eclipse.mat.query.refined.RefinedTable;
-import org.eclipse.mat.query.refined.RefinedTree;
import org.eclipse.mat.report.IOutputter;
import org.eclipse.mat.report.Renderer;
@@ -42,8 +40,8 @@
public void embedd(Context context, IResult result, Writer writer) throws IOException
{
// add column names to first row
- Column[] columns = (result instanceof RefinedTable) ? ((RefinedTable) result).getColumns()
- : ((RefinedTree) result).getColumns();
+ Column[] columns = (result instanceof IResultTable) ? ((IResultTable) result).getColumns()
+ : ((IResultTree) result).getColumns();
Filter.ValueConverter[] filter = new Filter.ValueConverter[columns.length];
for (int columnIndex = 0; columnIndex < columns.length; columnIndex++)
@@ -61,9 +59,9 @@
writer.append("\n"); //$NON-NLS-1$
// add data records
- if (result instanceof RefinedTable)
+ if (result instanceof IResultTable)
{
- RefinedTable table = ((RefinedTable) result);
+ IResultTable table = ((IResultTable) result);
int limit = context.hasLimit() ? Math.min(table.getRowCount(), context.getLimit()) : table.getRowCount();
for (int row = 0; row < limit; row++)
@@ -82,10 +80,10 @@
writer.append("\n"); //$NON-NLS-1$
}
}
- else if (result instanceof RefinedTree)
+ else if (result instanceof IResultTree)
{
// export only first level of the RefinedTree
- RefinedTree tree = (RefinedTree) result;
+ IResultTree tree = (IResultTree) result;
List<?> elements = tree.getElements();
int limit = context.hasLimit() ? Math.min(elements.size(), context.getLimit()) : elements.size();
diff --git a/plugins/org.eclipse.mat.report/src/org/eclipse/mat/report/internal/HtmlOutputter.java b/plugins/org.eclipse.mat.report/src/org/eclipse/mat/report/internal/HtmlOutputter.java
index d2429d3..79f93f2 100644
--- a/plugins/org.eclipse.mat.report/src/org/eclipse/mat/report/internal/HtmlOutputter.java
+++ b/plugins/org.eclipse.mat.report/src/org/eclipse/mat/report/internal/HtmlOutputter.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2008, 2019 SAP AG and IBM Corporation.
+ * Copyright (c) 2008, 2021 SAP AG and IBM Corporation.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
@@ -242,10 +242,19 @@
}
else
{
- if (columns[i].isNumeric())
- artefact.append("<td align=\"right\">");
- else
- artefact.append("<td>");
+ switch (columns[i].getAlign())
+ {
+ case RIGHT:
+ artefact.append("<td align=\"right\">");
+ break;
+ case CENTER:
+ artefact.append("<td align=\"center\">");
+ break;
+ case LEFT:
+ default:
+ artefact.append("<td>");
+ break;
+ }
artefact.append(totalsRow.getLabel(i)).append("</td>");
}
}
@@ -395,10 +404,19 @@
{
if (context.isColumnVisible(columnIndex))
{
- if (columns[columnIndex].isNumeric())
- artefact.append("<td align=\"right\">");
- else
- artefact.append("<td>");
+ switch (columns[columnIndex].getAlign())
+ {
+ case RIGHT:
+ artefact.append("<td align=\"center\">");
+ break;
+ case CENTER:
+ artefact.append("<td align=\"center\">");
+ break;
+ case LEFT:
+ default:
+ artefact.append("<td>");
+ break;
+ }
renderColumnValue(context, artefact, structured, columns, row, columnIndex);
artefact.append("</td>");
diff --git a/plugins/org.eclipse.mat.report/src/org/eclipse/mat/report/internal/RenderingInfo.java b/plugins/org.eclipse.mat.report/src/org/eclipse/mat/report/internal/RenderingInfo.java
index 3e2c6e8..4cfc15e 100644
--- a/plugins/org.eclipse.mat.report/src/org/eclipse/mat/report/internal/RenderingInfo.java
+++ b/plugins/org.eclipse.mat.report/src/org/eclipse/mat/report/internal/RenderingInfo.java
@@ -1,14 +1,15 @@
/*******************************************************************************
- * Copyright (c) 2008, 2010 SAP AG.
+ * Copyright (c) 2008, 2021 SAP AG and IBM Corporation.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
- * https://www.eclipse.org/legal/epl-2.0/
- *
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* SAP AG - initial API and implementation
+ * Andrew Johnson - bug fixes for different renderers
*******************************************************************************/
package org.eclipse.mat.report.internal;
@@ -19,7 +20,9 @@
import org.eclipse.mat.query.IQueryContext;
import org.eclipse.mat.query.IResult;
import org.eclipse.mat.report.IOutputter;
+import org.eclipse.mat.report.Params;
import org.eclipse.mat.report.QuerySpec;
+import org.eclipse.mat.report.RendererRegistry;
import org.eclipse.mat.report.Spec;
/* package */class RenderingInfo implements IOutputter.Context
@@ -89,7 +92,21 @@
if (filename == null)
{
- filename = ResultRenderer.DIR_PAGES + '/' + child.getId() + ".html"; //$NON-NLS-1$
+ /*
+ * Guess the format that might be used.
+ * For example, "stacktrace with involved local variables"
+ * in leak suspects TextResult as HTML with a default
+ * mode of csv.
+ * The file name is decided here, but the true format is
+ * decided later.
+ */
+ String format = child.params().get(Params.FORMAT, "html"); //$NON-NLS-1$
+ IOutputter outputter = RendererRegistry.instance().match(format, result.getClass());
+ if (outputter == null && result instanceof QuerySpec)
+ outputter = RendererRegistry.instance().match(format, ((QuerySpec)result).getResult().getClass());
+ if (outputter == null)
+ format = "html"; //$NON-NLS-1$
+ filename = ResultRenderer.DIR_PAGES + '/' + child.getId() + "." + format; //$NON-NLS-1$
dataFile.setSuggestedFile(filename);
}
diff --git a/plugins/org.eclipse.mat.report/src/org/eclipse/mat/report/internal/TextEmitter.java b/plugins/org.eclipse.mat.report/src/org/eclipse/mat/report/internal/TextEmitter.java
index b9b5802..7e38da6 100644
--- a/plugins/org.eclipse.mat.report/src/org/eclipse/mat/report/internal/TextEmitter.java
+++ b/plugins/org.eclipse.mat.report/src/org/eclipse/mat/report/internal/TextEmitter.java
@@ -104,7 +104,7 @@
}
// add column names to the result buffer
- for (int i = 0; i < numberOfColumns; i++)
+ for (int i = 0; i < order.length; i++)
{
int col = order[i];
if (i != 0)
@@ -120,7 +120,7 @@
for (Object item : items)
{
boolean addLineBreak = true;
- for (int i = 0; i < numberOfColumns; i++)
+ for (int i = 0; i < order.length; i++)
{
int columnIndex = order[i];
if (shouldSuppressLineBreak(item))
@@ -207,7 +207,7 @@
append(align(getDisplayableColumnValue(children[j], col), align[col], length - level.length(),
numberOfColumns == 1));
// add the rest of the columns
- for (int i = 1; i < numberOfColumns; i++)
+ for (int i = 1; i < order.length; i++)
{
col = order[i];
append(COLUMN_SEPARATOR);
@@ -324,7 +324,7 @@
{
StringBuilder dashes = new StringBuilder();
int dashesLength = 0;
- for (int i = 0; i < numberOfColumns; i++)
+ for (int i = 0; i < order.length; i++)
{
int col = order[i];
// column separator
diff --git a/plugins/org.eclipse.mat.report/src/org/eclipse/mat/report/internal/TextOutputter.java b/plugins/org.eclipse.mat.report/src/org/eclipse/mat/report/internal/TextOutputter.java
index 2eb70f0..47d9632 100644
--- a/plugins/org.eclipse.mat.report/src/org/eclipse/mat/report/internal/TextOutputter.java
+++ b/plugins/org.eclipse.mat.report/src/org/eclipse/mat/report/internal/TextOutputter.java
@@ -14,19 +14,23 @@
import java.io.IOException;
import java.io.Writer;
+import java.util.Arrays;
import java.util.List;
import org.eclipse.mat.query.Column;
import org.eclipse.mat.query.Column.Alignment;
+import org.eclipse.mat.query.IDecorator;
import org.eclipse.mat.query.IResult;
import org.eclipse.mat.query.IResultTable;
import org.eclipse.mat.query.IResultTree;
+import org.eclipse.mat.query.ISelectionProvider;
import org.eclipse.mat.query.refined.Filter;
-import org.eclipse.mat.query.refined.RefinedTable;
-import org.eclipse.mat.query.refined.RefinedTree;
+import org.eclipse.mat.query.refined.RefinedStructuredResult;
+import org.eclipse.mat.query.refined.TotalsRow;
import org.eclipse.mat.query.results.TextResult;
import org.eclipse.mat.report.IOutputter;
import org.eclipse.mat.report.Renderer;
+import org.eclipse.mat.util.VoidProgressListener;
@Renderer(target = "txt", result = { IResultTree.class, IResultTable.class, TextResult.class })
public class TextOutputter extends OutputterBase implements IOutputter
@@ -45,11 +49,11 @@
writer.append(((TextResult) result).getText());
writer.append(LINE_SEPARATOR);
}
- else if (result instanceof RefinedTable)
+ else if (result instanceof IResultTable)
{
new RefinedTableTextEmitter(context, result, writer).doCopy();
}
- else if (result instanceof RefinedTree)
+ else if (result instanceof IResultTree)
{
new RefinedTreeTextEmitter(context, result, writer).doCopy();
}
@@ -111,10 +115,17 @@
order = new int[columns.length];
filter = new Filter.ValueConverter[columns.length];
+ int orderIndex = 0;
for (int columnIndex = 0; columnIndex < columns.length; columnIndex++)
{
filter[columnIndex] = (Filter.ValueConverter) columns[columnIndex].getData(Filter.ValueConverter.class);
- order[columnIndex] = columnIndex;
+ /*
+ * It's a bit complicated to handle invisible columns
+ * because the columnIndex may be used to lookup values.
+ * Omit the column from the ordering.
+ */
+ if (context.isColumnVisible(columnIndex))
+ order[orderIndex++] = columnIndex;
Alignment alignment = columns[columnIndex].getAlign();
switch (alignment)
{
@@ -128,13 +139,9 @@
align[columnIndex] = ALIGN_LEFT;
break;
}
-
- // TODO it's a bit complicated to handle invisible columns
- // because the columnIndex may be used to lookup values
- // in the underlying IResult, so we would need to add a mapping
- //
- // if (context.isColumnVisible(columnIndex))
}
+ if (orderIndex < order.length)
+ order = Arrays.copyOf(order, orderIndex);
}
@Override
@@ -197,7 +204,7 @@
private static class RefinedTableTextEmitter extends StructuredResultTextEmitter
{
- private RefinedTable table;
+ private IResultTable table;
public RefinedTableTextEmitter(Context context, IResult result, Writer writer)
{
@@ -207,17 +214,38 @@
@Override
protected void initialize(IResult result)
{
- this.table = (RefinedTable) result;
+ this.table = (IResultTable) result;
}
@Override
protected Object[] getItems()
{
int rows = context.hasLimit() ? Math.min(table.getRowCount(), context.getLimit()) : table.getRowCount();
- Object[] result = new Object[rows];
+ int rows1 = context.isTotalsRowVisible() && table instanceof RefinedStructuredResult ? rows + 1 : rows;
+ int rows0 = 0;
+ if (table instanceof RefinedStructuredResult && ((RefinedStructuredResult) table).hasActiveFilter())
+ {
+ ++rows1;
+ rows0 = 1;
+ }
+ Object[] result = new Object[rows1];
for (int i = 0; i < rows; i++)
{
- result[i] = table.getRow(i);
+ result[rows0 + i] = table.getRow(i);
+ }
+ if (table instanceof RefinedStructuredResult)
+ {
+ RefinedStructuredResult rsr = (RefinedStructuredResult)table;
+ if (rows0 == 1)
+ result[0] = rsr.getFilter();
+ if (rows1 > rows0 + rows)
+ {
+ List<Object> subList = Arrays.asList(result).subList(rows0, rows0 + rows);
+ final TotalsRow totalsRow = rsr.buildTotalsRow(subList);
+ totalsRow.setVisibleItems(rows);
+ rsr.calculateTotals(subList, totalsRow, new VoidProgressListener());
+ result[rows1 - 1] = totalsRow;
+ }
}
return result;
}
@@ -231,25 +259,73 @@
@Override
protected String getItemValue(Object item, int columnIndex)
{
+ if (item instanceof Filter[])
+ {
+ Filter f[] = (Filter[])item;
+ String fv = f[columnIndex].getCriteria();
+ if (fv == null)
+ fv = ""; //$NON-NLS-1$
+ return fv;
+ }
+ if (item instanceof TotalsRow)
+ {
+ TotalsRow tr = (TotalsRow)item;
+ return tr.getLabel(columnIndex);
+ }
+ if (table instanceof RefinedStructuredResult)
+ return ((RefinedStructuredResult)table).getFormattedColumnValue(item, columnIndex);
return getStringValue(table.getColumnValue(item, columnIndex), filter[columnIndex]);
}
@Override
protected String getDisplayableColumnValue(Object item, int index)
{
+ if (item instanceof Filter[])
+ {
+ Filter f[] = (Filter[])item;
+ String fv = f[index].getCriteria();
+ if (fv == null)
+ fv = ""; //$NON-NLS-1$
+ return fv;
+ }
+ if (item instanceof TotalsRow)
+ {
+ TotalsRow tr = (TotalsRow)item;
+ return tr.getLabel(index);
+ }
+ if (table instanceof RefinedStructuredResult)
+ {
+ String v = ((RefinedStructuredResult)table).getFormattedColumnValue(item, index);
+ IDecorator dec = table.getColumns()[index].getDecorator();
+ if (dec != null)
+ {
+ String prefix = dec.prefix(item);
+ String suffix = dec.suffix(item);
+ if (prefix != null)
+ if (suffix != null)
+ v = prefix + " " + v + " " + suffix; //$NON-NLS-1$ //$NON-NLS-2$
+ else
+ v = prefix + " " + v; //$NON-NLS-1$
+ else
+ if (suffix != null)
+ v = v + " " + suffix; //$NON-NLS-1$
+ }
+ return v;
+ }
return getStringValue(table.getColumnValue(item, index), filter[index]);
}
@Override
protected boolean isExpanded(Object item)
{
- return table.isExpanded(item);
+ return false;
}
}
private static class RefinedTreeTextEmitter extends StructuredResultTextEmitter
{
- private RefinedTree tree;
+ private IResultTree tree;
+ private ISelectionProvider sel;
public RefinedTreeTextEmitter(Context context, IResult result, Writer writer)
{
@@ -259,18 +335,48 @@
@Override
protected void initialize(IResult result)
{
- tree = (RefinedTree) result;
+ tree = (IResultTree) result;
+ if (result instanceof ISelectionProvider)
+ sel = (ISelectionProvider)result;
+ else
+ sel = ISelectionProvider.EMPTY;
}
@Override
protected Object[] getItems()
{
List<?> elements = tree.getElements();
+ return getItems(elements);
+ }
+
+ protected Object[] getItems(List<?> elements)
+ {
int rows = context.hasLimit() ? Math.min(elements.size(), context.getLimit()) : elements.size();
- Object[] result = new Object[rows];
+ int rows1 = context.isTotalsRowVisible() && tree instanceof RefinedStructuredResult ? rows + 1 : rows;
+ int rows0 = 0;
+ if (tree instanceof RefinedStructuredResult && ((RefinedStructuredResult) tree).hasActiveFilter())
+ {
+ ++rows1;
+ rows0 = 1;
+ }
+ Object[] result = new Object[rows1];
for (int i = 0; i < rows; i++)
{
- result[i] = elements.get(i);
+ result[rows0 + i] = elements.get(i);
+ }
+ if (tree instanceof RefinedStructuredResult)
+ {
+ RefinedStructuredResult rsr = (RefinedStructuredResult)tree;
+ if (rows0 == 1)
+ result[0] = rsr.getFilter();
+ if (rows1 > rows0 + rows)
+ {
+ List<Object> subList = Arrays.asList(result).subList(rows0, rows0 + rows);
+ final TotalsRow totalsRow = rsr.buildTotalsRow(subList);
+ totalsRow.setVisibleItems(rows);
+ rsr.calculateTotals(subList, totalsRow, new VoidProgressListener());
+ result[rows1 - 1] = totalsRow;
+ }
}
return result;
}
@@ -284,19 +390,185 @@
@Override
protected String getItemValue(Object item, int columnIndex)
{
+ if (item instanceof Filter[])
+ {
+ Filter f[] = (Filter[])item;
+ String fv = f[columnIndex].getCriteria();
+ if (fv == null)
+ fv = ""; //$NON-NLS-1$
+ return fv;
+ }
+ if (item instanceof TotalsRow)
+ {
+ TotalsRow tr = (TotalsRow)item;
+ return tr.getLabel(columnIndex);
+ }
+ if (tree instanceof RefinedStructuredResult)
+ return ((RefinedStructuredResult)tree).getFormattedColumnValue(item, columnIndex);
return getStringValue(tree.getColumnValue(item, columnIndex), filter[columnIndex]);
}
@Override
protected String getDisplayableColumnValue(Object item, int index)
{
+ if (item instanceof Filter[])
+ {
+ Filter f[] = (Filter[])item;
+ String fv = f[index].getCriteria();
+ if (fv == null)
+ fv = ""; //$NON-NLS-1$
+ return fv;
+ }
+ if (item instanceof TotalsRow)
+ {
+ TotalsRow tr = (TotalsRow)item;
+ return tr.getLabel(index);
+ }
+ if (tree instanceof RefinedStructuredResult)
+ {
+ String v = ((RefinedStructuredResult)tree).getFormattedColumnValue(item, index);
+ IDecorator dec = tree.getColumns()[index].getDecorator();
+ if (dec != null)
+ {
+ String prefix = dec.prefix(item);
+ String suffix = dec.suffix(item);
+ if (prefix != null)
+ if (suffix != null)
+ v = prefix + " " + v + " " + suffix; //$NON-NLS-1$ //$NON-NLS-2$
+ else
+ v = prefix + " " + v; //$NON-NLS-1$
+ else
+ if (suffix != null)
+ v = v + " " + suffix; //$NON-NLS-1$
+ }
+ return v;
+ }
return getStringValue(tree.getColumnValue(item, index), filter[index]);
}
@Override
protected boolean isExpanded(Object item)
{
- return tree.isExpanded(item);
+ if (item instanceof TotalsRow)
+ return false;
+ return sel.isExpanded(item);
}
+
+ @Override
+ protected boolean shouldAddNextLine(Object item)
+ {
+ return isExpanded(item) && toPrint(item);
+ }
+
+ private boolean toPrint(Object item)
+ {
+ return true;
+ }
+
+ @Override
+ protected boolean shouldProcessChild(Object child)
+ {
+ return true;
+ }
+
+ @Override
+ protected Object[] getChildren(Object item)
+ {
+ if (item instanceof TotalsRow)
+ return null;
+ if (tree.hasChildren(item))
+ {
+ List<?> children = tree.getChildren(item);
+ if (children != null)
+ return getItems(children);
+ }
+ return null;
+ }
+
+ protected int getColumnLength(Object[] items, Object[] objColumns, int columnNumber)
+ {
+ int lengthToCompare = 0;
+ String header = getColumnName(objColumns[columnNumber]);
+ int length = header != null ? header.length() : 0;
+
+ for (int i = 0; i < items.length; i++)
+ {
+ lengthToCompare = getDisplayableColumnValue(items[i], columnNumber).length();
+
+ if (lengthToCompare > length)
+ length = lengthToCompare;
+
+ if (isExpanded(items[i]))
+ {
+ if (columnNumber == order[0])
+ lengthToCompare = compare(items[i], length, columnNumber, new StringBuilder());
+ else
+ lengthToCompare = getOtherColumnLength(items[i], length, columnNumber);
+
+ }
+ if (lengthToCompare > length)
+ length = lengthToCompare;
+ }
+
+ return length;
+ }
+
+ private int getOtherColumnLength(Object item, int length, int columnNumber)
+ {
+ int lengthToCompare = 0;
+ Object[] children = getChildren(item);
+ if (children != null)
+ {
+ for (int i = 0; i < children.length; i++)
+ {
+ //if (selection != null && skip(children[i]))
+ // continue;
+ String columnText = getDisplayableColumnValue(children[i], columnNumber);
+ if (columnText != null)
+ lengthToCompare = columnText.length();
+ if (lengthToCompare > length)
+ length = lengthToCompare;
+
+ if (isExpanded(children[i]))
+ {
+ lengthToCompare = getOtherColumnLength(children[i], length, columnNumber);
+ if (lengthToCompare > length)
+ length = lengthToCompare;
+ }
+
+ }
+ }
+ return length;
+ }
+
+ private int compare(Object item, int length, int columnNumber, StringBuilder level)
+ {
+ int lengthToCompare = 0;
+ Object[] children = getChildren(item);
+ if (children != null)
+ {
+ for (int i = 0; i < children.length; i++)
+ {
+ //if (selection != null && skip(children[i]))
+ // continue;
+ level = getLevel(level, children.length, i);
+ lengthToCompare = getDisplayableColumnValue(children[i], columnNumber).length() + level.length();
+ if (lengthToCompare > length)
+ length = lengthToCompare;
+
+ if (isExpanded(children[i]))
+ {
+ lengthToCompare = compare(children[i], length, columnNumber, level);
+ if (lengthToCompare > length)
+ length = lengthToCompare;
+ }
+ if (level.length() >= 3)
+ level.delete(level.length() - 3, level.length());
+
+ }
+ }
+ return length;
+ }
+
}
}
diff --git a/plugins/org.eclipse.mat.tests/src/org/eclipse/mat/tests/snapshot/GeneralSnapshotTests.java b/plugins/org.eclipse.mat.tests/src/org/eclipse/mat/tests/snapshot/GeneralSnapshotTests.java
index 8be535d..25f9a1b 100644
--- a/plugins/org.eclipse.mat.tests/src/org/eclipse/mat/tests/snapshot/GeneralSnapshotTests.java
+++ b/plugins/org.eclipse.mat.tests/src/org/eclipse/mat/tests/snapshot/GeneralSnapshotTests.java
@@ -25,7 +25,9 @@
import static org.hamcrest.collection.IsEmptyCollection.emptyCollectionOf;
import static org.hamcrest.core.IsInstanceOf.instanceOf;
import static org.hamcrest.core.IsNull.nullValue;
+import static org.hamcrest.number.OrderingComparison.lessThanOrEqualTo;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
@@ -41,10 +43,12 @@
import java.io.Serializable;
import java.nio.charset.Charset;
import java.nio.charset.IllegalCharsetNameException;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
+import java.util.List;
import java.util.Set;
import java.util.Stack;
import java.util.regex.Matcher;
@@ -714,9 +718,11 @@
FileInputStream fis = new FileInputStream(f);
try
{
- if (!f.getName().endsWith(".html"))
+ if (!f.getName().endsWith(".html")
+ && !f.getName().endsWith(".csv")
+ && !f.getName().endsWith(".txt"))
{
- // Not HTML
+ // Not HTML or CSV or text
return;
}
String encoding = System.getProperty("file.encoding", "UTF-8"); //$NON-NLS-1$ //$NON-NLS-2$
@@ -734,6 +740,17 @@
char cbuf[] = new char[(int)f.length()];
int l = ir.read(cbuf);
String s = new String(cbuf, 0, l);
+ // An empty result with a filename ending .csv might be forced into HTML type
+ if (f.getName().endsWith(".csv") && !s.startsWith("<!DOCTYPE HTML PUBLIC"))
+ {
+ checkCSV(f, s);
+ return;
+ }
+ if (f.getName().endsWith(".txt"))
+ {
+ checkTXT(f, s);
+ return;
+ }
/*
* All these checks are approximate and would be confused
@@ -741,9 +758,9 @@
*/
// Some basic checks
- assertThat("Expected charset", s, containsString("content=\"text/html;charset=" + encoding + "\""));
- assertThat("Possible double escaping <", s, not(containsString("&lt;")));
- assertThat("Possible double escaping &", s, not(containsString("&amp;")));
+ assertThat(f + " Expected charset", s, containsString("content=\"text/html;charset=" + encoding + "\""));
+ assertThat(f + " Possible double escaping <", s, not(containsString("&lt;")));
+ assertThat(f + " Possible double escaping &", s, not(containsString("&amp;")));
/*
* Rough test for bad tag - might indicate unescaped '<'.
@@ -947,6 +964,153 @@
}
}
+ /**
+ * Check a text file generated from a table or tree.
+ */
+ private void checkTXT(File f, String s)
+ {
+ String lines[] = s.split("\r?\n");
+ if (lines.length >= 2 && lines[1].matches("-+"))
+ {
+ // Check the last row is dashes
+ assertThat(f.getPath(), lines[lines.length - 1], equalTo(lines[1]));
+ // Check that no row is longer than the dashes
+ int maxlen = lines[1].length();
+ for (int i = 0; i < lines.length; ++i)
+ {
+ assertThat(f+" "+(i+1)+":"+lines[i], lines[i].length(), lessThanOrEqualTo(maxlen));
+ }
+ // Check the divisions on each line match the header
+ for (int i = 2; i < lines.length - 1; ++i)
+ {
+ // Sometimes the text has a line feed, splitting the file
+ String line = "";
+ l: for (int p = i; p >= 2; --p)
+ {
+ line = lines[p] + "\n "+ line;
+ for (int j = lines[0].indexOf('|'); j >= 0; j = lines[0].indexOf('|', j +1))
+ {
+ // Try to fix up split lines
+ if (line.length() < maxlen && (line.length() < j || line.charAt(j) != '|'))
+ continue l;
+ }
+ break;
+ }
+ for (int j = lines[0].indexOf('|'); j >= 0; j = lines[0].indexOf('|', j +1))
+ {
+ assertThat(f+" "+(i+1)+":"+(j+1)+" "+line, line.length(), greaterThan(j));
+ assertThat(f+" "+(i+1)+":"+(j+1)+" "+line, line.charAt(j), equalTo('|'));
+ }
+ }
+ if (lines.length > 2)
+ {
+ // check the first row is not blank (empty filter row?)
+ assertFalse(lines[2].matches("[ |]+"));
+ }
+ }
+ }
+
+ /**
+ * Check a CSV (comma separated value) file.
+ */
+ private void checkCSV(File f, String s)
+ {
+ List<List<String>>all = split(f, s);
+ for (List<String> l : all)
+ {
+ assertThat(l.size(), equalTo(all.get(0).size()));
+ }
+ }
+
+ /**
+ * Split a CSV file into lines and fields
+ * @param f
+ * @param s
+ * @return a list of lists of fields
+ */
+ public List<List<String>>split(File f, String s) {
+ List<List<String>>res1 = new ArrayList<List<String>>();
+ List<String>res = new ArrayList<String>();
+ boolean inquote = false;
+ boolean prevquote = false;
+ boolean prevcr = false;
+ StringBuilder sb = new StringBuilder();
+ for (char c : s.toCharArray())
+ {
+ if (inquote)
+ {
+ if (c == '"')
+ {
+ prevquote = true;
+ inquote = false;
+ }
+ else
+ {
+ sb.append(c);
+ prevquote = false;
+ }
+ } else {
+ switch (c) {
+ case '"':
+ assertFalse(f+" "+s, prevcr);
+ if (prevquote) {
+ sb.append(c);
+ inquote = true;
+ prevquote = false;
+ } else {
+ inquote = true;
+ prevquote = false;
+ }
+ break;
+ case ',':
+ assertFalse(f+" "+s, prevcr);
+ res.add(sb.toString());
+ sb.setLength(0);
+ break;
+ case '\r':
+ assertFalse(f+" "+s, prevcr);
+ prevcr = true;
+ break;
+ case '\n':
+ assertFalse(f+" "+s, inquote);
+ res.add(sb.toString());
+ sb.setLength(0);
+ res1.add(res);
+ res = new ArrayList<String>();
+ break;
+ default:
+ assertFalse(f+" "+s, prevcr);
+ sb.append(c);
+ break;
+ }
+ }
+ }
+ if (sb.length() > 0)
+ assertThat(f.toString(), sb.toString(), equalTo(""));
+ assertThat(f+" "+res,res.size(), equalTo(0));
+ return res1;
+ }
+
+ @Test
+ public void testAllQueriesReportText() throws SnapshotException, IOException
+ {
+ IProgressListener checkListener = new CheckedProgressListener(collector);
+ SnapshotQuery query = SnapshotQuery.parse("default_report org.eclipse.mat.tests:all -params format=txt", snapshot);
+ IResult t = query.execute(checkListener);
+ assertNotNull(t);
+ checkHTMLResult(t);
+ }
+
+ @Test
+ public void testAllQueriesReportCSV() throws SnapshotException, IOException
+ {
+ IProgressListener checkListener = new CheckedProgressListener(collector);
+ SnapshotQuery query = SnapshotQuery.parse("default_report org.eclipse.mat.tests:all -params format=csv", snapshot);
+ IResult t = query.execute(checkListener);
+ assertNotNull(t);
+ checkHTMLResult(t);
+ }
+
@Test
public void listEntries() throws SnapshotException
{
diff --git a/plugins/org.eclipse.mat.ui/src/org/eclipse/mat/ui/Messages.java b/plugins/org.eclipse.mat.ui/src/org/eclipse/mat/ui/Messages.java
index 0395b25..26b701f 100644
--- a/plugins/org.eclipse.mat.ui/src/org/eclipse/mat/ui/Messages.java
+++ b/plugins/org.eclipse.mat.ui/src/org/eclipse/mat/ui/Messages.java
@@ -1,10 +1,10 @@
/*******************************************************************************
- * Copyright (c) 2010, 2020 SAP AG, IBM Corporation and others.
+ * Copyright (c) 2010, 2021 SAP AG, IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
- * https://www.eclipse.org/legal/epl-2.0/
- *
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
@@ -94,10 +94,12 @@
public static String ExportActions_Export;
public static String ExportActions_ExportCSV;
public static String ExportActions_ExportHTML;
+ public static String ExportActions_ExportTXT;
public static String ExportActions_ExportToCSV;
public static String ExportActions_ExportToHTML;
public static String ExportActions_ExportToTxt;
public static String ExportActions_PlainText;
+ public static String ExportActions_PlainText2;
public static String ExportActions_ZippedWebPage;
public static String FieldsContentProvider_Displayed;
public static String FileOpenDialogEditor_ChooseFile;
diff --git a/plugins/org.eclipse.mat.ui/src/org/eclipse/mat/ui/internal/viewer/ExportActions.java b/plugins/org.eclipse.mat.ui/src/org/eclipse/mat/ui/internal/viewer/ExportActions.java
index e4224e7..5c95474 100644
--- a/plugins/org.eclipse.mat.ui/src/org/eclipse/mat/ui/internal/viewer/ExportActions.java
+++ b/plugins/org.eclipse.mat.ui/src/org/eclipse/mat/ui/internal/viewer/ExportActions.java
@@ -1,14 +1,15 @@
/*******************************************************************************
- * Copyright (c) 2008, 2010 SAP AG.
+ * Copyright (c) 2008, 2021 SAP AG and IBM Corporation.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
- * https://www.eclipse.org/legal/epl-2.0/
- *
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* SAP AG - initial API and implementation
+ * Andrew Johnson - export of text using renderer
*******************************************************************************/
package org.eclipse.mat.ui.internal.viewer;
@@ -17,6 +18,7 @@
import java.io.IOException;
import java.io.PrintWriter;
import java.net.URL;
+import java.util.Arrays;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.Set;
@@ -49,6 +51,8 @@
import org.eclipse.swt.widgets.FileDialog;
import org.eclipse.swt.widgets.MessageBox;
import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.TableItem;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeItem;
@@ -84,56 +88,7 @@
final int limit = (controlItem != null && controlItem.getTotals() != null) ? controlItem.getTotals()
.getVisibleItems() : 25;
- // extract expanded items
-
- // problem:
- // because the result tree can create objects on every #getChilden()
- // call, objects in the hash map will not match and the expansion
- // state of nested objects will not be acknowledged
-
- // the requirement to implement #equals and #hashCode seems too
- // heavy (and might not help, because one and the same object might
- // show up multiple times in the tree, but the decision has too be
- // made structurally)
- if (control instanceof Tree)
- {
- Tree tree = (Tree) control;
-
- LinkedList<TreeItem> stack = new LinkedList<TreeItem>();
-
- TreeItem[] items = tree.getItems();
- for (TreeItem treeItem : items)
- stack.add(treeItem);
-
- final Set<Object> expanded = new HashSet<Object>();
- while (!stack.isEmpty())
- {
- TreeItem item = stack.removeFirst();
- if (item.getExpanded())
- {
- Object data = item.getData();
- if (data != null)
- expanded.add(data);
-
- items = item.getItems();
- for (TreeItem treeItem : items)
- stack.add(treeItem);
- }
- }
-
- result.setSelectionProvider(new ISelectionProvider()
- {
- public boolean isExpanded(Object row)
- {
- return expanded.contains(row);
- }
-
- public boolean isSelected(Object row)
- {
- return false;
- }
- });
- }
+ expandedTree(control, result);
new Job(Messages.ExportActions_ExportHTML)
{
@@ -164,6 +119,90 @@
}
}
+ private static void expandedTree(Control control, RefinedStructuredResult result)
+ {
+ // extract expanded items
+
+ // problem:
+ // because the result tree can create objects on every #getChilden()
+ // call, objects in the hash map will not match and the expansion
+ // state of nested objects will not be acknowledged
+
+ // the requirement to implement #equals and #hashCode seems too
+ // heavy (and might not help, because one and the same object might
+ // show up multiple times in the tree, but the decision has too be
+ // made structurally)
+ if (control instanceof Tree)
+ {
+ Tree tree = (Tree) control;
+
+ LinkedList<TreeItem> stack = new LinkedList<TreeItem>();
+ Set<TreeItem> selects = new HashSet<TreeItem>(Arrays.asList(tree.getSelection()));
+ TreeItem[] items = tree.getItems();
+ for (TreeItem treeItem : items)
+ stack.add(treeItem);
+
+ final Set<Object> expanded = new HashSet<Object>();
+ final Set<Object> selected = new HashSet<Object>();
+ while (!stack.isEmpty())
+ {
+ TreeItem item = stack.removeFirst();
+ if (selects.contains(item))
+ {
+ Object data = item.getData();
+ if (data != null)
+ selected.add(data);
+ }
+ if (item.getExpanded())
+ {
+ Object data = item.getData();
+ if (data != null)
+ expanded.add(data);
+
+ items = item.getItems();
+ for (TreeItem treeItem : items)
+ stack.add(treeItem);
+ }
+ }
+
+ result.setSelectionProvider(new ISelectionProvider()
+ {
+ public boolean isExpanded(Object row)
+ {
+ return expanded.contains(row);
+ }
+
+ public boolean isSelected(Object row)
+ {
+ return selected.contains(row);
+ }
+ });
+ }
+ else if (control instanceof Table)
+ {
+ Table table = (Table)control;
+ final Set<Object> selected = new HashSet<Object>();
+ for (TableItem item : table.getSelection())
+ {
+ Object data = item.getData();
+ if (data != null)
+ selected.add(data);
+ }
+ result.setSelectionProvider(new ISelectionProvider()
+ {
+ public boolean isExpanded(Object row)
+ {
+ return false;
+ }
+
+ public boolean isSelected(Object row)
+ {
+ return selected.contains(row);
+ }
+ });
+ }
+ }
+
/* package */static class CsvExport extends Action
{
private Control control;
@@ -227,25 +266,69 @@
/* package */static class TxtExport extends Action
{
private Control control;
+ private IResult result;
+ private IQueryContext queryContext;
- public TxtExport(Control control)
+ public TxtExport(Control control, IResult result, IQueryContext queryContext)
{
super(Messages.ExportActions_ExportToTxt, MemoryAnalyserPlugin
.getImageDescriptor(MemoryAnalyserPlugin.ISharedImages.EXPORT_TXT));
this.control = control;
+ this.result = result;
+ this.queryContext = queryContext;
}
@Override
public void run()
{
ExportDialog dialog = new ExportDialog(control.getShell(), //
- new String[] { Messages.ExportActions_PlainText }, //
- new String[] { "*.txt" });//$NON-NLS-1$
- String fileName = dialog.open();
+ new String[] { Messages.ExportActions_PlainText, Messages.ExportActions_PlainText2 }, //
+ new String[] { "*.txt", "*.txt" });//$NON-NLS-1$ //$NON-NLS-2$
+ final String fileName = dialog.open();
if (fileName == null)
return;
- Copy.exportToTxtFile(control, fileName);
+ // Old version of export
+ if (dialog.dlg.getFilterIndex() < 1) {
+ Copy.exportToTxtFile(control, fileName);
+ return;
+ }
+
+ if (result instanceof RefinedStructuredResult)
+ expandedTree(control, (RefinedStructuredResult)result);
+
+ new Job(Messages.ExportActions_ExportTXT)
+ {
+
+ @Override
+ protected IStatus run(IProgressMonitor monitor)
+ {
+ PrintWriter writer = null;
+
+ try
+ {
+ IOutputter outputter = RendererRegistry.instance().match("txt", result.getClass());//$NON-NLS-1$
+ writer = new PrintWriter(new FileWriter(fileName));
+ outputter.process(new ContextImpl(queryContext, //
+ new File(fileName).getParentFile()), result, writer);
+ writer.flush();
+ writer.close();
+ }
+ catch (IOException e)
+ {
+ return ErrorHelper.createErrorStatus(e);
+ }
+ finally
+ {
+ if (writer != null)
+ writer.close();
+ }
+
+ return Status.OK_STATUS;
+ }
+
+ }.schedule();
+
}
}
diff --git a/plugins/org.eclipse.mat.ui/src/org/eclipse/mat/ui/internal/viewer/RefinedResultViewer.java b/plugins/org.eclipse.mat.ui/src/org/eclipse/mat/ui/internal/viewer/RefinedResultViewer.java
index c4fd7ee..ae7d8ec 100644
--- a/plugins/org.eclipse.mat.ui/src/org/eclipse/mat/ui/internal/viewer/RefinedResultViewer.java
+++ b/plugins/org.eclipse.mat.ui/src/org/eclipse/mat/ui/internal/viewer/RefinedResultViewer.java
@@ -1,10 +1,10 @@
/*******************************************************************************
- * Copyright (c) 2008, 2020 SAP AG and IBM Corporation
+ * Copyright (c) 2008, 2021 SAP AG and IBM Corporation
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
- * https://www.eclipse.org/legal/epl-2.0/
- *
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
@@ -78,7 +78,6 @@
import org.eclipse.swt.widgets.MessageBox;
import org.eclipse.swt.widgets.Text;
import org.eclipse.swt.widgets.Widget;
-import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.actions.ActionFactory;
import org.eclipse.ui.themes.ColorUtil;
@@ -761,7 +760,7 @@
{
menu.add(new ExportActions.HtmlExport(control, result, context));
menu.add(new ExportActions.CsvExport(control, result, context));
- menu.add(new ExportActions.TxtExport(control));
+ menu.add(new ExportActions.TxtExport(control, result, context));
}
};
diff --git a/plugins/org.eclipse.mat.ui/src/org/eclipse/mat/ui/messages.properties b/plugins/org.eclipse.mat.ui/src/org/eclipse/mat/ui/messages.properties
index 72950fb..e102e82 100644
--- a/plugins/org.eclipse.mat.ui/src/org/eclipse/mat/ui/messages.properties
+++ b/plugins/org.eclipse.mat.ui/src/org/eclipse/mat/ui/messages.properties
@@ -1,10 +1,10 @@
###############################################################################
-# Copyright (c) 2010,2020 SAP AG, IBM Corporation and others.
+# Copyright (c) 2010,2021 SAP AG, IBM Corporation and others.
# All rights reserved. This program and the accompanying materials
# are made available under the terms of the Eclipse Public License 2.0
# which accompanies this distribution, and is available at
-# https://www.eclipse.org/legal/epl-2.0/
-#
+# https://www.eclipse.org/legal/epl-2.0/
+#
# SPDX-License-Identifier: EPL-2.0
#
# Contributors:
@@ -116,10 +116,12 @@
ExportActions_Export=Export
ExportActions_ExportCSV=Export CSV
ExportActions_ExportHTML=Export HTML
+ExportActions_ExportTXT=Export TXT
ExportActions_ExportToCSV=Export to CSV...
ExportActions_ExportToHTML=Export to HTML...
ExportActions_ExportToTxt=Export to TXT...
ExportActions_PlainText=Plain Text(*.txt)
+ExportActions_PlainText2=Plain Text(*.txt) - new version
ExportActions_ZippedWebPage=Zipped Web Page (*.zip)
FieldsContentProvider_Displayed={0} out of {1} displayed
FileOpenDialogEditor_ChooseFile=Choose File...