blob: dabba59863a9898e2d514b00d78fac2251920766 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.netbeans.modules.bugtracking.commons;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.MouseAdapter;
import java.awt.font.TextAttribute;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.OutputStream;
import java.lang.reflect.Method;
import java.text.DateFormat;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.ResourceBundle;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.AbstractAction;
import javax.swing.Action;
import static javax.swing.Action.NAME;
import javax.swing.GroupLayout;
import javax.swing.GroupLayout.ParallelGroup;
import javax.swing.GroupLayout.SequentialGroup;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.LayoutStyle;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import org.netbeans.api.progress.ProgressHandle;
import org.netbeans.api.progress.ProgressHandleFactory;
import org.netbeans.modules.team.ide.spi.IDEServices;
import org.openide.DialogDescriptor;
import org.openide.DialogDisplayer;
import org.openide.NotifyDescriptor;
import org.openide.awt.HtmlBrowser;
import org.openide.cookies.EditorCookie;
import org.openide.cookies.OpenCookie;
import org.openide.filesystems.FileChooserBuilder;
import org.openide.filesystems.FileObject;
import org.openide.filesystems.FileUtil;
import org.openide.loaders.DataObject;
import org.openide.loaders.DataObjectNotFoundException;
import org.openide.modules.Places;
import org.openide.util.ChangeSupport;
import org.openide.util.Exceptions;
import org.openide.util.Lookup;
import org.openide.util.NbBundle;
import org.openide.util.Utilities;
/**
*
* @author Jan Stola
* // XXX merge with bugzilla and jira
*/
public class AttachmentsPanel extends JPanel {
private static final Logger LOG = Logger.getLogger(AttachmentsPanel.class.getName());
private boolean hadNoAttachments = true;
private List<AttachmentPanel> newAttachments;
private JLabel noneLabel;
private LinkButton createNewButton;
private LinkButton attachLogFileButton;
private JLabel dummyCreateLabel = new JLabel();
private JLabel dummyAttachLabel = new JLabel();
private Method maxMethod;
private JComponent parentPanel;
private final ChangeSupport supp;
private ChangeListener changeList;
public interface NBBugzillaCallback {
public String getLogFilePath();
public String getLogFileContentType();
public String getLogFileDescription();
public void showLogFile();
}
public AttachmentsPanel(JComponent parentPanel) {
this.parentPanel = parentPanel;
this.supp = new ChangeSupport(this);
setBackground(UIManager.getColor("TextArea.background")); // NOI18N
ResourceBundle bundle = NbBundle.getBundle(AttachmentsPanel.class);
noneLabel = new JLabel(bundle.getString("AttachmentsPanel.noneLabel.text")); // NOI18N
createNewButton = new LinkButton(new CreateNewAction());
createNewButton.getAccessibleContext().setAccessibleDescription(bundle.getString("AttachmentPanels.createNewButton.AccessibleContext.accessibleDescription")); // NOI18N
try {
maxMethod = GroupLayout.Group.class.getDeclaredMethod("calculateMaximumSize", int.class); // NOI18N
maxMethod.setAccessible(true);
} catch (NoSuchMethodException nsmex) {
LOG.log(Level.INFO, nsmex.getMessage(), nsmex);
}
}
public void setAttachments(List<? extends Attachment> attachments) {
setAttachments(attachments, Collections.<AttachmentInfo>emptyList(), null);
}
public void setAttachments(List<? extends Attachment> attachments, List<? extends AttachmentInfo> unsubmittedAttachments,
NBBugzillaCallback nbCallback) {
if(nbCallback != null) {
attachLogFileButton = new LinkButton(new CreateNewAction(nbCallback));
attachLogFileButton.getAccessibleContext().setAccessibleDescription(NbBundle.getBundle(AttachmentsPanel.class).getString("AttachmentPanels.attachLogFileButton.AccessibleContext.accessibleDescription")); // NOI18N
}
hadNoAttachments = attachments.isEmpty();
newAttachments = new LinkedList<AttachmentPanel>();
removeAll();
GroupLayout layout = new GroupLayout(this);
GroupLayout.ParallelGroup horizontalGroup = layout.createParallelGroup(GroupLayout.Alignment.LEADING);
GroupLayout.SequentialGroup verticalGroup = layout.createSequentialGroup();
ResourceBundle bundle = NbBundle.getBundle(AttachmentsPanel.class);
GroupLayout.SequentialGroup newVerticalGroup = layout.createSequentialGroup();
boolean noAttachments = hadNoAttachments;
if(attachLogFileButton != null) {
SequentialGroup sg = layout.createSequentialGroup();
sg.addComponent(noneLabel)
.addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
.addComponent(noAttachments ? createNewButton : dummyCreateLabel)
.addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
.addComponent(noAttachments ? attachLogFileButton : dummyAttachLabel);
horizontalGroup.addGroup(sg);
} else {
horizontalGroup.addGroup(layout.createSequentialGroup()
.addComponent(noneLabel)
.addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
.addComponent(noAttachments ? createNewButton : dummyCreateLabel));
}
if(attachLogFileButton != null) {
ParallelGroup pg = layout.createParallelGroup(GroupLayout.Alignment.BASELINE);
pg.addComponent(noneLabel)
.addComponent(noAttachments ? createNewButton : dummyCreateLabel)
.addComponent(noAttachments ? attachLogFileButton : dummyAttachLabel);
verticalGroup.addGroup(pg);
} else {
verticalGroup.addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE)
.addComponent(noneLabel)
.addComponent(noAttachments ? createNewButton : dummyCreateLabel));
}
dummyCreateLabel.setVisible(false);
dummyAttachLabel.setVisible(false);
noneLabel.setVisible(noAttachments);
updateButtonText(noAttachments);
if (noAttachments) {
// noneLabel + createNewButton
verticalGroup.addGroup(newVerticalGroup);
} else {
List<JPanel> panels = new ArrayList<JPanel>();
JLabel descriptionLabel = new JLabel(bundle.getString("AttachmentsPanel.table.description")); // NOI18N
JLabel filenameLabel = new JLabel(bundle.getString("AttachmentsPanel.table.filename")); // NOI18N
JLabel dateLabel = new JLabel(bundle.getString("AttachmentsPanel.table.date")); // NOI18N
JLabel authorLabel = new JLabel(bundle.getString("AttachmentsPanel.table.author")); // NOI18N
makeBold(descriptionLabel);
makeBold(filenameLabel);
makeBold(dateLabel);
makeBold(authorLabel);
GroupLayout.ParallelGroup descriptionGroup = layout.createParallelGroup();
GroupLayout.ParallelGroup filenameGroup = layout.createParallelGroup();
GroupLayout.ParallelGroup dateGroup = layout.createParallelGroup();
GroupLayout.ParallelGroup authorGroup = layout.createParallelGroup();
int descriptionWidth = Math.max(descriptionLabel.getPreferredSize().width, 150);
descriptionGroup.addComponent(descriptionLabel, descriptionWidth, descriptionWidth, descriptionWidth);
filenameGroup.addComponent(filenameLabel);
dateGroup.addComponent(dateLabel);
authorGroup.addComponent(authorLabel);
JPanel panel = createHighlightPanel();
panels.add(panel);
horizontalGroup.addGroup(layout.createSequentialGroup()
.addGroup(descriptionGroup)
.addPreferredGap(descriptionLabel, filenameLabel, LayoutStyle.ComponentPlacement.UNRELATED)
.addGroup(filenameGroup)
.addPreferredGap(filenameLabel, dateLabel, LayoutStyle.ComponentPlacement.UNRELATED)
.addGroup(dateGroup)
.addPreferredGap(dateLabel, authorLabel, LayoutStyle.ComponentPlacement.UNRELATED)
.addGroup(authorGroup));
verticalGroup.addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING, false)
.addComponent(panel, 0, 0, Short.MAX_VALUE)
.addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE)
.addComponent(descriptionLabel)
.addComponent(filenameLabel)
.addComponent(dateLabel)
.addComponent(authorLabel)));
for (Attachment attachment : attachments) {
boolean isPatch = attachment.isPatch() && hasPatchUtils();
boolean isDeprecated = attachment.isDeprecated();
String description = attachment.getDesc();
String filename = attachment.getFilename();
Date date = attachment.getDate();
String author = attachment.getAuthor();
String authorName = attachment.getAuthorName();
authorName = ((authorName != null) && (authorName.trim().length() > 0)) ? authorName : author;
descriptionLabel = new JLabel(description);
LinkButton filenameButton = new LinkButton();
LinkButton patchButton = null;
JLabel lBrace = null;
JLabel rBrace = null;
GroupLayout.SequentialGroup hPatchGroup = null;
if (isPatch) {
patchButton = new LinkButton();
lBrace = new JLabel("("); // NOI18N
rBrace = new JLabel(")"); // NOI18N
hPatchGroup = layout.createSequentialGroup()
.addComponent(filenameButton)
.addPreferredGap(filenameButton, lBrace, LayoutStyle.ComponentPlacement.RELATED)
.addComponent(lBrace)
.addComponent(patchButton)
.addComponent(rBrace);
}
JPopupMenu menu = menuFor(attachment, patchButton);
filenameButton.setAction(attachment.getOpenAction());
filenameButton.setText(filename);
if(isDeprecated) {
strikeThrough(filenameButton);
}
filenameButton.getAccessibleContext().setAccessibleDescription(NbBundle.getMessage(AttachmentsPanel.class, "AttachmentPanels.filenameButton.AccessibleContext.accessibleDescription")); // NOI18N
dateLabel = new JLabel(date != null ? DateFormat.getDateInstance().format(date) : ""); // NOI18N
JComponent authorComponent;
if(author.indexOf("@") > -1) { // NOI18N
authorComponent = new LinkButton.MailtoButton(authorName, NbBundle.getMessage(AttachmentsPanel.class, "AttachmentPanel.authorButton.AccessibleContext.accessibleDescription"), author); // NOI18N
} else {
authorComponent = new JLabel(authorName);
}
descriptionLabel.setComponentPopupMenu(menu);
if(isDeprecated) {
strikeThrough(descriptionLabel);
}
filenameButton.setComponentPopupMenu(menu);
dateLabel.setComponentPopupMenu(menu);
authorComponent.setComponentPopupMenu(menu);
descriptionGroup.addComponent(descriptionLabel, 0, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE);
if (isPatch) {
lBrace.setComponentPopupMenu(menu);
patchButton.setComponentPopupMenu(menu);
rBrace.setComponentPopupMenu(menu);
filenameGroup.addGroup(hPatchGroup);
} else {
filenameGroup.addComponent(filenameButton);
}
dateGroup.addComponent(dateLabel);
authorGroup.addComponent(authorComponent);
panel = createHighlightPanel();
panel.addMouseListener(new MouseAdapter() {}); // Workaround for bug 6272233
panel.setComponentPopupMenu(menu);
panels.add(panel);
GroupLayout.ParallelGroup pGroup = layout.createParallelGroup(GroupLayout.Alignment.BASELINE);
pGroup.addComponent(descriptionLabel);
pGroup.addComponent(filenameButton);
if (isPatch) {
pGroup.addComponent(lBrace);
pGroup.addComponent(patchButton);
pGroup.addComponent(rBrace);
}
pGroup.addComponent(dateLabel);
pGroup.addComponent(authorComponent);
verticalGroup
.addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING, false)
.addComponent(panel, 0, 0, Short.MAX_VALUE)
.addGroup(pGroup));
}
verticalGroup.addGroup(newVerticalGroup);
int groupWidth = 0;
if (maxMethod != null) {
try {
groupWidth = (Integer)maxMethod.invoke(horizontalGroup, 0);
} catch (Exception ex) {
LOG.log(Level.INFO, ex.getMessage(), ex);
}
}
for (JPanel p : panels) {
horizontalGroup.addComponent(p, 0, 0, groupWidth);
}
}
if(attachLogFileButton != null) {
SequentialGroup sg = layout.createSequentialGroup();
sg.addComponent(noAttachments ? dummyCreateLabel : createNewButton)
.addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
.addComponent(noAttachments ? dummyAttachLabel : attachLogFileButton)
.addGap(0, 0, Short.MAX_VALUE);
horizontalGroup.addGroup(sg);
} else {
horizontalGroup.addGroup(layout.createSequentialGroup()
.addComponent(noAttachments ? dummyCreateLabel : createNewButton)
.addGap(0, 0, Short.MAX_VALUE));
}
if(attachLogFileButton != null) {
ParallelGroup pg = layout.createParallelGroup(GroupLayout.Alignment.BASELINE);
pg.addComponent(noAttachments ? dummyCreateLabel : createNewButton)
.addComponent(noAttachments ? dummyAttachLabel : attachLogFileButton);
verticalGroup.addPreferredGap(LayoutStyle.ComponentPlacement.RELATED);
verticalGroup.addGroup(pg);
} else {
verticalGroup.addPreferredGap(LayoutStyle.ComponentPlacement.RELATED);
verticalGroup.addComponent(noAttachments ? dummyCreateLabel : createNewButton);
}
layout.setHorizontalGroup(horizontalGroup);
layout.setVerticalGroup(verticalGroup);
((CreateNewAction)createNewButton.getAction()).setLayoutGroups(horizontalGroup, newVerticalGroup);
if(attachLogFileButton != null) {
((CreateNewAction)attachLogFileButton.getAction()).setLayoutGroups(horizontalGroup, newVerticalGroup);
}
setLayout(layout);
for (AttachmentInfo newAttachment : unsubmittedAttachments) {
((CreateNewAction)createNewButton.getAction()).createAttachment(newAttachment);
}
}
protected void strikeThrough(JComponent cmp) {
Map attributes = cmp.getFont().getAttributes();
attributes.put(TextAttribute.STRIKETHROUGH, TextAttribute.STRIKETHROUGH_ON);
cmp.setFont(cmp.getFont().deriveFont(attributes));
}
@Override
public Dimension getMinimumSize() {
return new Dimension(0, super.getMinimumSize().height);
}
/**
* Programmatically calls create new attachment method
*/
public final void createAttachment () {
createNewButton.doClick();
}
/**
* Programmatically calls attach log method
*/
public final void createNbLogAttachment () {
if (attachLogFileButton != null) {
attachLogFileButton.doClick();
}
}
private JPopupMenu menuFor(Attachment attachment, LinkButton patchButton) {
JPopupMenu menu = new JPopupMenu();
menu.add(attachment.getOpenAction());
Action openInStackAnalyzerAction = attachment.getOpenInStackAnalyzerAction();
if(openInStackAnalyzerAction != null) {
menu.add(openInStackAnalyzerAction);
}
menu.add(attachment.getSaveAction());
if (attachment.isPatch() && hasPatchUtils()) {
Action action = attachment.getApplyPatchAction();
menu.add(action);
patchButton.setAction(action);
// Lower the first letter
String label = patchButton.getText();
patchButton.setText(label.substring(0,1).toLowerCase()+label.substring(1));
patchButton.getAccessibleContext().setAccessibleDescription(NbBundle.getMessage(AttachmentsPanel.class, "AttachmentPanels.patchButton.AccessibleContext.accessibleDescription")); // NOI18N
}
if (attachment.canBeDeleted()) {
Action action = attachment.getDeleteAction();
if (action != null) {
menu.add(action);
}
}
return menu;
}
private void updateButtonText(boolean noAttachments) {
String txt = NbBundle.getMessage(AttachmentsPanel.class, "AttachmentsPanel.createNewButton.text"); // NOI18N
createNewButton.setText(noAttachments ? ('('+txt+')') : txt); // NOI18N
if(attachLogFileButton != null) {
txt = NbBundle.getMessage(AttachmentsPanel.class, "AttachmentsPanel.attachLogFileButton.text"); // NOI18N
attachLogFileButton.setText(noAttachments ? ('('+txt+')') : txt); // NOI18N
}
}
private void makeBold(JLabel label) {
Font font = label.getFont().deriveFont(Font.BOLD);
label.setFont(font);
}
private JPanel createHighlightPanel() {
JPanel panel = new JPanel();
// PENDING what color (e.g. what key from UIDefaults) should I use?
panel.setBackground(UIUtils.getSectionPanelBackground());
add(panel);
return panel;
}
private PropertyChangeListener deletedListener;
PropertyChangeListener getDeletedListener() {
if (deletedListener == null) {
deletedListener = new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
if (AttachmentPanel.PROP_DELETED.equals(evt.getPropertyName())) {
supp.fireChange();
if (hadNoAttachments) {
for (AttachmentPanel panel : newAttachments) {
if (!panel.isDeleted()) {
return;
}
}
// The last attachment deleted
noneLabel.setVisible(true);
switchHelper();
updateButtonText(true);
}
}
}
};
}
return deletedListener;
}
private void switchHelper() {
JLabel temp = new JLabel();
GroupLayout layout = (GroupLayout)getLayout();
layout.replace(dummyCreateLabel, temp);
layout.replace(createNewButton, dummyCreateLabel);
layout.replace(temp, createNewButton);
if(attachLogFileButton != null) {
layout.replace(dummyAttachLabel, temp);
layout.replace(attachLogFileButton, dummyAttachLabel);
layout.replace(temp, attachLogFileButton);
}
}
@NbBundle.Messages("IssuePanel.attachment.noDescription=<no description>")
public List<AttachmentInfo> getNewAttachments() {
List<AttachmentInfo> infos = new ArrayList<AttachmentInfo>(newAttachments.size());
for (AttachmentPanel attachment : newAttachments) {
if (!attachment.isDeleted()) {
AttachmentInfo info = new AttachmentInfo();
info.file = attachment.getFile();
info.description = attachment.getDescription();
info.contentType = attachment.getContentType();
info.isPatch = attachment.isPatch();
if (info.description.trim().isEmpty()) {
info.description = Bundle.IssuePanel_attachment_noDescription();
}
infos.add(info);
}
}
return infos;
}
public void addChangeListener (ChangeListener changeListener) {
supp.addChangeListener(changeListener);
}
public void removeChangeListener (ChangeListener changeListener) {
supp.removeChangeListener(changeListener);
}
public static final class AttachmentInfo {
private File file;
private String description;
private String contentType;
private boolean isPatch;
public String getContentType () {
return contentType;
}
public String getDescription () {
return description;
}
public File getFile () {
return file;
}
public boolean isPatch () {
return isPatch;
}
public void setDescription(String description) {
this.description = description;
}
public void setContentType (String contentType) {
this.contentType = contentType;
}
public void setFile (File file) {
this.file = file;
}
public void setIsPatch (boolean isPatch) {
this.isPatch = isPatch;
}
}
class CreateNewAction extends AbstractAction {
private final NBBugzillaCallback nbCallback;
public CreateNewAction() {
this(null);
}
public CreateNewAction(NBBugzillaCallback nbCallback) {
this.nbCallback = nbCallback;
}
private GroupLayout.ParallelGroup horizontalGroup;
private GroupLayout.SequentialGroup verticalGroup;
void setLayoutGroups(GroupLayout.ParallelGroup horizontalGroup,
GroupLayout.SequentialGroup verticalGroup) {
this.horizontalGroup = horizontalGroup;
this.verticalGroup = verticalGroup;
}
@Override
public void actionPerformed(ActionEvent e) {
createAttachment(null);
}
private void createAttachment (AttachmentInfo newAttachment) {
AttachmentPanel attachment = new AttachmentPanel(nbCallback);
attachment.setBackground(UIUtils.getSectionPanelBackground());
horizontalGroup.addComponent(attachment, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE);
verticalGroup.addPreferredGap(LayoutStyle.ComponentPlacement.RELATED);
verticalGroup.addComponent(attachment, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE);
if (noneLabel.isVisible()) {
noneLabel.setVisible(false);
switchHelper();
updateButtonText(false);
}
attachment.addPropertyChangeListener(getDeletedListener());
if (newAttachment != null) {
attachment.setAttachment(newAttachment.getFile(), newAttachment.getDescription(),
newAttachment.getContentType(), newAttachment.isPatch());
}
if(nbCallback != null) {
File f = new File(Places.getUserDirectory(), nbCallback.getLogFilePath());
if(f.exists()) {
attachment.setAttachment(f, nbCallback.getLogFileDescription(), nbCallback.getLogFileContentType(), false); // NOI18N
}
attachment.browseButton.setEnabled(false);
attachment.fileField.setEnabled(false);
attachment.fileTypeCombo.setEnabled(false);
attachment.patchChoice.setEnabled(false);
} else {
attachment.viewButton.setVisible(false);
}
newAttachments.add(attachment);
UIUtils.keepFocusedComponentVisible(attachment, parentPanel);
revalidate();
attachment.addChangeListener(getChangeListener());
attachment.fileField.requestFocus();
if (nbCallback != null) {
supp.fireChange();
}
}
}
private ChangeListener getChangeListener () {
if (changeList == null) {
changeList = new ChangeListener() {
@Override
public void stateChanged (ChangeEvent e) {
supp.fireChange();
}
};
}return changeList;
}
private static boolean hasPatchUtils() {
IDEServices ideServices = Support.getInstance().getIDEServices();
return ideServices != null && ideServices.providesPatchUtils();
}
private static boolean hasStackTraceUtils() {
IDEServices ideServices = Support.getInstance().getIDEServices();
return ideServices != null && ideServices.providesOpenInStackAnalyzer();
}
public static interface Attachment {
public boolean isPatch ();
public boolean isDeprecated ();
public Action getOpenAction ();
public Action getApplyPatchAction ();
public Action getSaveAction ();
public Action getDeleteAction ();
public Action getOpenInStackAnalyzerAction();
public String getDesc ();
public String getFilename ();
public Date getDate ();
public String getAuthor ();
public String getAuthorName ();
public boolean canBeDeleted ();
}
public abstract static class AbstractAttachment implements Attachment {
private OpenAttachmentAction openAttachmentAction;
private SaveAttachmentAction saveAttachmentAction;
private ApplyPatchAction applyPatchAction;
private OpenInStackAnalyzerAction openStacktraceAction;
@Override
public Action getOpenAction () {
if (openAttachmentAction == null) {
openAttachmentAction = new OpenAttachmentAction();
}
return openAttachmentAction;
}
@Override
public Action getApplyPatchAction () {
if(hasPatchUtils()) {
if (applyPatchAction == null) {
applyPatchAction = new ApplyPatchAction();
}
return applyPatchAction;
} else {
return null;
}
}
@Override
public Action getSaveAction () {
if (saveAttachmentAction == null) {
saveAttachmentAction = new SaveAttachmentAction();
}
return saveAttachmentAction;
}
@Override
public Action getOpenInStackAnalyzerAction() {
if(Boolean.getBoolean("bugtracking.experimental.issue.openInStackAnalyzer") && hasStackTraceUtils()) {
if (openStacktraceAction == null) {
openStacktraceAction = new OpenInStackAnalyzerAction();
}
return openStacktraceAction;
} else {
return null;
}
}
@Override
public Action getDeleteAction () {
return null;
}
protected abstract void getAttachementData (OutputStream os);
protected abstract String getContentType ();
@Override
public boolean canBeDeleted () {
return false;
}
@Override
public boolean isDeprecated() {
return false;
}
public void open() {
// XXX
String progressFormat = NbBundle.getMessage(OpenAttachmentAction.class, "Attachment.open.progress"); //NOI18N
String progressMessage = MessageFormat.format(progressFormat, getFilename());
final ProgressHandle handle = ProgressHandleFactory.createHandle(progressMessage);
handle.start();
handle.switchToIndeterminate();
Support.getInstance().getParallelRP().post(new Runnable() {
@Override
public void run() {
try {
File file = saveToTempFile();
String contentType = getContentType();
if ("image/png".equals(contentType) //NOI18N
|| "image/gif".equals(contentType) //NOI18N
|| "image/jpeg".equals(contentType)) { //NOI18N
HtmlBrowser.URLDisplayer.getDefault().showURL(Utilities.toURI(file).toURL());
} else {
file = FileUtil.normalizeFile(file);
FileObject fob = FileUtil.toFileObject(file);
DataObject dob = DataObject.find(fob);
OpenCookie open = dob.getCookie(OpenCookie.class);
if (open != null) {
open.open();
} else {
// PENDING
}
}
} catch (DataObjectNotFoundException dnfex) {
LOG.log(Level.INFO, dnfex.getMessage(), dnfex);
} catch (IOException ioex) {
LOG.log(Level.INFO, ioex.getMessage(), ioex);
} finally {
handle.finish();
}
}
});
}
public void openInStackAnalyzer() {
String progressFormat = NbBundle.getMessage(OpenAttachmentAction.class, "Attachment.open.progress"); //NOI18N
String progressMessage = MessageFormat.format(progressFormat, getFilename());
final ProgressHandle handle = ProgressHandleFactory.createHandle(progressMessage);
handle.start();
handle.switchToIndeterminate();
Support.getInstance().getParallelRP().post(new Runnable() {
@Override
public void run() {
try {
final IDEServices ideServices = Lookup.getDefault().lookup(IDEServices.class);
if(ideServices == null || !ideServices.providesOpenInStackAnalyzer()) {
return;
}
final File file = saveToTempFile();
if(file.length() > 1024 * 1024) {
long size = file.length();
Object[] arr = {
getFilename(),
new Long (size), // bytes
new Long (size / 1024 + 1), // kilobytes
new Long (size / (1024 * 1024)), // megabytes
new Long (size / (1024 * 1024 * 1024)), // gigabytes
};
DialogDescriptor c = new DialogDescriptor(
NbBundle.getMessage(AttachmentPanel.class, "MSG_ObjectIsTooBig", arr),
NbBundle.getMessage(AttachmentPanel.class, "CTL_TooBig"),
true,
DialogDescriptor.YES_NO_OPTION, DialogDescriptor.NO_OPTION, null);
if(DialogDisplayer.getDefault().notify(c) != NotifyDescriptor.YES_OPTION) {
return;
}
}
if(isBinary(file)) {
DialogDescriptor c = new DialogDescriptor(
NbBundle.getMessage(AttachmentPanel.class, "MSG_BinaryContent", new Object[] {getFilename()}),
NbBundle.getMessage(AttachmentPanel.class, "CTL_BinaryContent"),
true,
DialogDescriptor.YES_NO_OPTION, DialogDescriptor.NO_OPTION, null);
if(DialogDisplayer.getDefault().notify(c) != NotifyDescriptor.YES_OPTION) {
return;
}
return;
}
final BufferedReader fr = new BufferedReader(new FileReader(file));
// final StringBuilder sb = new StringBuilder();
// String ln = fr.readLine();
// while(ln != null) {
// sb.append(ln);
// ln = fr.readLine();
// if(ln != null) {
// sb.append("\n"); // NOI18N
// }
// }
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
try {
ideServices.openInStackAnalyzer(fr);
} finally {
if(fr != null) {
try {
// relying on this beeing called synchronously
fr.close();
} catch (IOException ex) {
Exceptions.printStackTrace(ex);
}
}
}
}
});
} catch (IOException ioex) {
LOG.log(Level.INFO, ioex.getMessage(), ioex);
} finally {
handle.finish();
}
}
private boolean isBinary(File file) {
FileObject fo = FileUtil.toFileObject(file);
try {
DataObject dao = DataObject.find(fo);
if (dao.getCookie(EditorCookie.class) == null) {
return true;
}
}catch (DataObjectNotFoundException e) {
// not found, continue
}
String mime = fo.getMIMEType();
if (mime != null && mime.equals("application/octet-stream")) {
return true;
}
return false;
}
});
}
private void saveToFile() {
final File file = new FileChooserBuilder(AttachmentsPanel.class)
.setFilesOnly(true).showSaveDialog();
if (file != null) {
String progressFormat = NbBundle.getMessage(
SaveAttachmentAction.class,
"Attachment.saveToFile.progress"); //NOI18N
String progressMessage = MessageFormat.format(progressFormat, getFilename());
final ProgressHandle handle = ProgressHandleFactory.createHandle(progressMessage);
handle.start();
handle.switchToIndeterminate();
Support.getInstance().getParallelRP().post(new Runnable() {
@Override
public void run() {
try {
getAttachmentData(file);
} catch (IOException ioex) {
LOG.log(Level.INFO, ioex.getMessage(), ioex);
} finally {
handle.finish();
}
}
});
}
}
private void applyPatch() {
String progressFormat = NbBundle.getMessage(AttachmentsPanel.class,"Attachment.applyPatch.progress"); //NOI18N
String progressMessage = MessageFormat.format(progressFormat, getFilename());
final ProgressHandle handle = ProgressHandleFactory.createHandle(progressMessage);
handle.start();
handle.switchToIndeterminate();
Support.getInstance().getParallelRP().post(
new Runnable() {
@Override
public void run() {
IDEServices ideServices = Support.getInstance().getIDEServices();
if(ideServices != null) {
try {
ideServices.applyPatch(saveToTempFile());
} catch (IOException ex) {
LOG.log(Level.WARNING, ex.getMessage(), ex);
} finally {
handle.finish();
}
}
}
});
}
private File saveToTempFile () throws IOException {
String filename = getFilename();
int index = filename.lastIndexOf('.'); // NOI18N
String prefix = (index == -1) ? filename : filename.substring(0, index);
String suffix = (index == -1) ? null : filename.substring(index);
if (prefix.length()<3) {
prefix = prefix + "tmp"; //NOI18N
}
File file = File.createTempFile(prefix, suffix);
getAttachmentData(file);
return file;
}
private void getAttachmentData (File file) throws IOException {
FileOutputStream fos = null;
try {
fos = new FileOutputStream(file);
getAttachementData(fos);
} finally {
if (fos != null) {
try {
fos.close();
} catch (IOException ex) {
}
}
}
}
private class OpenAttachmentAction extends AbstractAction {
public OpenAttachmentAction() {
putValue(NAME, NbBundle.getMessage(
OpenAttachmentAction.class,
"Attachment.OpenAction.name")); //NOI18N
}
@Override
public void actionPerformed(ActionEvent e) {
open();
}
}
private class OpenInStackAnalyzerAction extends AbstractAction {
public OpenInStackAnalyzerAction() {
putValue(NAME, NbBundle.getMessage(
OpenAttachmentAction.class,
"Attachment.OpenInStackAction.name")); //NOI18N
}
@Override
public void actionPerformed(ActionEvent e) {
IDEServices ideServices = Lookup.getDefault().lookup(IDEServices.class);
if(ideServices != null && ideServices.providesOpenInStackAnalyzer()) {
openInStackAnalyzer();
}
}
}
private class SaveAttachmentAction extends AbstractAction {
public SaveAttachmentAction() {
putValue(NAME, NbBundle.getMessage(
SaveAttachmentAction.class,
"Attachment.SaveAction.name")); //NOI18N
}
@Override
public void actionPerformed(ActionEvent e) {
saveToFile();
}
}
private class ApplyPatchAction extends AbstractAction {
public ApplyPatchAction() {
putValue(NAME, NbBundle.getMessage(
ApplyPatchAction.class,
"Attachment.ApplyPatchAction.name"));//NOI18N
}
@Override
public void actionPerformed(ActionEvent e) {
applyPatch();
}
}
}
}