View Javadoc

1   /*
2    *  soapUI, copyright (C) 2004-2008 eviware.com 
3    *
4    *  soapUI is free software; you can redistribute it and/or modify it under the 
5    *  terms of version 2.1 of the GNU Lesser General Public License as published by 
6    *  the Free Software Foundation.
7    *
8    *  soapUI is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without 
9    *  even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
10   *  See the GNU Lesser General Public License for more details at gnu.org.
11   */
12  
13  package com.eviware.soapui.support.editor.inspectors.attachments;
14  
15  import java.awt.Component;
16  import java.awt.datatransfer.DataFlavor;
17  import java.awt.datatransfer.Transferable;
18  import java.awt.dnd.DnDConstants;
19  import java.awt.dnd.DropTarget;
20  import java.awt.dnd.DropTargetDragEvent;
21  import java.awt.dnd.DropTargetDropEvent;
22  import java.awt.dnd.DropTargetEvent;
23  import java.awt.dnd.DropTargetListener;
24  import java.awt.event.ActionEvent;
25  import java.awt.event.MouseAdapter;
26  import java.awt.event.MouseEvent;
27  import java.beans.PropertyChangeEvent;
28  import java.beans.PropertyChangeListener;
29  import java.io.File;
30  import java.io.FileNotFoundException;
31  import java.io.FileOutputStream;
32  import java.io.IOException;
33  import java.net.MalformedURLException;
34  import java.util.List;
35  
36  import javax.swing.AbstractListModel;
37  import javax.swing.ComboBoxModel;
38  import javax.swing.DefaultCellEditor;
39  import javax.swing.JButton;
40  import javax.swing.JComboBox;
41  import javax.swing.JFileChooser;
42  import javax.swing.JTable;
43  import javax.swing.event.ListSelectionEvent;
44  import javax.swing.event.ListSelectionListener;
45  
46  import com.eviware.soapui.SoapUI;
47  import com.eviware.soapui.impl.support.actions.ShowOnlineHelpAction;
48  import com.eviware.soapui.impl.wsdl.AttachmentContainer;
49  import com.eviware.soapui.impl.wsdl.MutableAttachmentContainer;
50  import com.eviware.soapui.impl.wsdl.support.HelpUrls;
51  import com.eviware.soapui.impl.wsdl.support.PathUtils;
52  import com.eviware.soapui.impl.wsdl.support.WsdlAttachment;
53  import com.eviware.soapui.model.iface.Attachment;
54  import com.eviware.soapui.model.iface.MessagePart.AttachmentPart;
55  import com.eviware.soapui.support.StringUtils;
56  import com.eviware.soapui.support.Tools;
57  import com.eviware.soapui.support.UISupport;
58  import com.eviware.soapui.support.components.JXToolBar;
59  
60  /***
61   * Utility Panel for displaying a table of attachments
62   * 
63   * @author emibre
64   */
65  
66  public class AttachmentsPanel extends javax.swing.JPanel
67  {
68  	private DropTarget dropTarget;
69  	private FileTransferHandler fileTransferHandler;
70  	private AttachmentsTableModel tableModel;
71  	private JFileChooser fc;
72  	private final AttachmentContainer container;
73  	private JButton exportBtn;
74  	private JButton reloadBtn;
75  
76  	/*** Creates new form FileTableList */
77  	public AttachmentsPanel(AttachmentContainer container)
78  	{
79  		this.container = container;
80  		initComponents();
81  		initFileTransfer();
82  	}
83  	
84  	public void release()
85  	{
86  		tableModel.release();
87  		if( attachmentPartCellEditor != null )
88  			attachmentPartCellEditor.release();
89  	}
90  
91  	private void initFileTransfer()
92  	{
93  		if( container instanceof MutableAttachmentContainer )
94  		{
95  			fileTransferHandler = new FileTransferHandler(tableModel);
96  			fileTable.setDragEnabled(true);
97  			fileTable.setTransferHandler(fileTransferHandler);
98  
99  			dropTarget = new DropTarget();
100 			dropTarget.setActive(true);
101 			try
102 			{
103 				dropTarget.addDropTargetListener(new DropTargetListener()
104 				{
105 					public void dragEnter(DropTargetDragEvent dtde)
106 					{
107 					}
108 
109 					public void dragExit(DropTargetEvent dte)
110 					{
111 					}
112 
113 					public void dragOver(DropTargetDragEvent dtde)
114 					{
115 					}
116 
117 					@SuppressWarnings("unchecked")
118 					public void drop(DropTargetDropEvent dtde)
119 					{
120 						try
121 						{
122 							dtde.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
123 							Transferable trans = dtde.getTransferable();
124 							List<File> files = (List<File>) trans.getTransferData(DataFlavor.javaFileListFlavor);
125 							for (File f : files)
126 							{
127 								System.out.println("Dropping file: " + f.getName());
128 
129 								Boolean retval = UISupport.confirmOrCancel("Cache attachment in request?", "Att Attachment");
130 								if (retval == null)
131 									return;
132 
133 								tableModel.addFile(f, retval);
134 							}
135 
136 						}
137 						catch (Exception e)
138 						{
139 							SoapUI.logError( e );
140 						}
141 					}
142 
143 					public void dropActionChanged(DropTargetDragEvent dtde)
144 					{
145 					}
146 				});
147 			}
148 			catch (Exception e)
149 			{
150 				SoapUI.logError( e );
151 			}
152 
153 			jScrollPane1.getViewport().setDropTarget(dropTarget);
154 		}
155 	}
156 
157 	private void initComponents()
158 	{
159 		jScrollPane1 = new javax.swing.JScrollPane();
160 		tableModel = new AttachmentsTableModel(container);
161 		fileTable = new JTable(tableModel);
162 
163 		if (container instanceof MutableAttachmentContainer)
164 		{
165 			attachmentPartCellEditor = new AttachmentPartCellEditor();
166 			fileTable.getColumnModel().getColumn(3).setCellEditor(attachmentPartCellEditor);
167 		}
168 
169 		setLayout(new java.awt.BorderLayout());
170 		jScrollPane1.setViewportView(fileTable);
171 
172 		add(jScrollPane1, java.awt.BorderLayout.CENTER);
173 
174 		jPanel1 = UISupport.createSmallToolbar();
175 		
176 		if (container instanceof MutableAttachmentContainer )
177 		{
178 			addFileBtn = UISupport.createToolbarButton(UISupport.createImageIcon( "/add_property.gif" ));
179 			removeBtn = UISupport.createToolbarButton(UISupport.createImageIcon( "/remove_property.gif" ));
180 			reloadBtn = UISupport.createToolbarButton(UISupport.createImageIcon( "/reload_properties.gif" ));
181 
182 			addFileBtn.setToolTipText( "Adds an attachment" );
183 			addFileBtn.addActionListener(new java.awt.event.ActionListener()
184 			{
185 				public void actionPerformed(java.awt.event.ActionEvent evt)
186 				{
187 					addFileBtnActionPerformed(evt);
188 				}
189 			});
190 
191 			jPanel1.addFixed(addFileBtn);
192 
193 			removeBtn.setToolTipText( "Removes the selected attachment" );
194 			removeBtn.setEnabled(false);
195 			removeBtn.addActionListener(new java.awt.event.ActionListener()
196 			{
197 				public void actionPerformed(java.awt.event.ActionEvent evt)
198 				{
199 					removeBtnActionPerformed(evt);
200 				}
201 			});
202 
203 			jPanel1.addFixed(removeBtn);
204 			
205 			reloadBtn.setToolTipText( "Reloads the selected attachment" );
206 			reloadBtn.setEnabled(false);
207 			reloadBtn.addActionListener(new java.awt.event.ActionListener()
208 			{
209 				public void actionPerformed(java.awt.event.ActionEvent evt)
210 				{
211 					reloadBtnActionPerformed(evt);
212 				}
213 			});
214 
215 			jPanel1.addFixed(reloadBtn);
216 		}
217 
218 		exportBtn = UISupport.createToolbarButton(UISupport.createImageIcon( "/export.gif" ));
219 		exportBtn.setToolTipText( "Exports the selected attachment to a file" );
220 		exportBtn.setEnabled(false);
221 		exportBtn.addActionListener(new java.awt.event.ActionListener()
222 		{
223 			public void actionPerformed(java.awt.event.ActionEvent evt)
224 			{
225 				exportBtnActionPerformed(evt);
226 			}
227 		});
228 
229 		jPanel1.addFixed(exportBtn);
230 		jPanel1.addGlue();
231 		jPanel1.addFixed( UISupport.createToolbarButton( new ShowOnlineHelpAction(HelpUrls.ATTACHMENTS_HELP_URL)));
232 		add(jPanel1, java.awt.BorderLayout.NORTH);
233 
234 		fileTable.getSelectionModel().addListSelectionListener(new ListSelectionListener()
235 		{
236 			public void valueChanged(ListSelectionEvent e)
237 			{
238 				if( removeBtn != null )
239 				{
240 					removeBtn.setEnabled(fileTable.getSelectedRowCount() > 0);
241 					reloadBtn.setEnabled(fileTable.getSelectedRowCount() > 0);
242 				}
243 				
244 				exportBtn.setEnabled(fileTable.getSelectedRowCount() > 0);
245 			}
246 		});
247 		
248 		fileTable.addMouseListener(new MouseAdapter()
249 		{
250 			public void mouseClicked(MouseEvent e)
251 			{
252 				if (e.getClickCount() < 2)
253 					return;
254 
255 				int ix = fileTable.getSelectedRow();
256 				if (ix == -1)
257 					return;
258 
259 				Attachment attachment = container.getAttachmentAt(ix);
260 				
261 				if( attachment.isCached() )
262 				{
263 					String name = attachment.getName();
264 					try
265 					{
266 						name = StringUtils.createFileName(name, '-' );
267 						File tempFile = File.createTempFile( "attachment-" + name.substring( 0, ix), name.substring(ix)  );
268 						exportAttachment(tempFile, attachment, false );
269 					}
270 					catch (Exception e1)
271 					{
272 						UISupport.showErrorMessage(e1);
273 					}
274 				}
275 				else
276 				{
277 					Tools.openURL(attachment.getUrl());
278 				}
279 			}
280 		});
281 	}
282 
283 	protected void exportBtnActionPerformed( ActionEvent evt )
284 	{
285 		File file = UISupport.getFileDialogs().saveAs( this, "Export Attachment.." );
286 		while( file != null && file.exists() && 
287 				 !UISupport.confirm( "File " + file.getName() + " exists, overwrite?", "Export Attachment" ))
288 		{
289 			file = UISupport.getFileDialogs().saveAs( this, "Export Attachment.." );
290 		}
291 		
292 		if( file != null )
293 		{
294 			Attachment attachment = tableModel.getAttachmentAt(fileTable.getSelectedRow());
295 			try
296 			{
297 				exportAttachment(file, attachment, true );
298 			}
299 			catch( Exception e )
300 			{
301 				UISupport.showErrorMessage( e );
302 			}
303 		}
304 	}
305 
306 	private void exportAttachment(File file, Attachment attachment, boolean showOpenQuery ) throws FileNotFoundException, IOException,
307 			Exception, MalformedURLException
308 	{
309 		FileOutputStream out = new FileOutputStream( file );
310 		
311 		long total = Tools.writeAll( out, attachment.getInputStream() );
312 		out.close();
313 		if( !showOpenQuery  || UISupport.confirm( "Written [" + total + "] bytes to " + file.getName() + ", open in browser?", "Saved File" ))
314 		{
315 			Tools.openURL( file.toURI().toURL().toString() );
316 		}
317 	}
318 	
319 	protected void reloadBtnActionPerformed( ActionEvent evt )
320 	{
321 		int selectedRow = fileTable.getSelectedRow();
322 		if( selectedRow == -1 )
323 			return;
324 		
325 		WsdlAttachment attachment = (WsdlAttachment) tableModel.getAttachmentAt(selectedRow);
326 		if( attachment == null )
327 			return;
328 		
329 		File file = UISupport.getFileDialogs().open( this, "Reload Attachment..", "*", "Any File", attachment.getUrl() );
330 		if( file != null )
331 		{
332 			Boolean retval = UISupport.confirmOrCancel("Cache attachment in request?", "Reload Attachment");
333 			if (retval == null)
334 				return;
335 			
336 			try
337 			{
338 				attachment.reload(file, retval);
339 				tableModel.fireTableRowsUpdated(selectedRow, selectedRow);
340 			}
341 			catch (IOException e)
342 			{
343 				UISupport.showErrorMessage(e);
344 			}
345 		}
346 	}
347 	
348 
349 	private void addFileBtnActionPerformed(java.awt.event.ActionEvent evt)
350 	{// GEN-FIRST:event_addFileBtnActionPerformed
351 		if (fc == null)
352 			fc = new JFileChooser();
353 
354 		String root = PathUtils.getExpandedResourceRoot( container.getModelItem());
355 		if( StringUtils.hasContent(root))
356 			fc.setCurrentDirectory( new File(root));
357 		
358 		int returnVal = fc.showOpenDialog(this);
359 
360 		if (returnVal == JFileChooser.APPROVE_OPTION)
361 		{
362 			File file = fc.getSelectedFile();
363 			Boolean retval = UISupport.confirmOrCancel("Cache attachment in request?", "Add Attachment");
364 			if (retval == null)
365 				return;
366 			try
367 			{
368 				tableModel.addFile(file, retval);
369 			}
370 			catch (IOException e)
371 			{
372 				UISupport.showErrorMessage(e);
373 			}
374 		}
375 		else
376 		{
377 			System.out.println("Open command cancelled by user.");
378 		}
379 	}// GEN-LAST:event_addFileBtnActionPerformed
380 
381 	private void removeBtnActionPerformed(java.awt.event.ActionEvent evt)
382 	{// GEN-FIRST:event_removeBtnActionPerformed
383 		if (UISupport.confirm("Remove selected attachments?", "Remove Attachments"))
384 			tableModel.removeAttachment(fileTable.getSelectedRows());
385 	}// GEN-LAST:event_removeBtnActionPerformed
386 
387 	// Variables declaration - do not modify//GEN-BEGIN:variables
388 	private javax.swing.JButton addFileBtn;
389 	private JTable fileTable;
390 	private JXToolBar jPanel1;
391 	private javax.swing.JScrollPane jScrollPane1;
392 	private javax.swing.JButton removeBtn;
393 	private AttachmentPartCellEditor attachmentPartCellEditor;
394 
395 	// End of variables declaration//GEN-END:variables
396 
397 	private class AttachmentPartCellEditor extends DefaultCellEditor
398 	{
399 		public AttachmentPartCellEditor()
400 		{
401 			super(new JComboBox(new PartsComboBoxModel()));
402 		}
403 
404 		public void release()
405 		{
406 			((PartsComboBoxModel) ((JComboBox) editorComponent).getModel()).release();
407 		}
408 
409 		public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column)
410 		{
411 			PartsComboBoxModel model = ((PartsComboBoxModel) ((JComboBox) editorComponent).getModel());
412 			((JComboBox) editorComponent).setModel( model.init(tableModel.getAttachmentAt(row)) );
413 			
414 			
415 			return super.getTableCellEditorComponent(table, value, isSelected, row, column);
416 		}
417 	}
418 
419 	private final class PartsComboBoxModel extends AbstractListModel implements ComboBoxModel, PropertyChangeListener
420 	{
421 		private Attachment attachment;
422 		private AttachmentPart[] parts;
423 		
424 		public PartsComboBoxModel()
425 		{
426 			container.addAttachmentsChangeListener( this );
427 		}
428 
429 		public void release()
430 		{
431 			container.removeAttachmentsChangeListener( this );
432 		}
433 
434 		public PartsComboBoxModel init(Attachment attachment)
435 		{
436 			this.attachment = attachment;
437 			
438 			int previousPartsCount = parts == null ? 0 : parts.length;
439 			
440 			parts = container.getDefinedAttachmentParts();
441 			if( previousPartsCount < parts.length )
442 			{
443 				fireIntervalAdded( this, previousPartsCount, parts.length );
444 			}
445 			else if( previousPartsCount > parts.length )
446 			{
447 				fireIntervalRemoved( this, parts.length-1, previousPartsCount );
448 			}
449 			
450 			fireContentsChanged( this, 0, parts.length-1 );
451 			
452 			return this;
453 		}
454 
455 		public Object getElementAt(int index)
456 		{
457 			return parts == null ? null : parts[index].getName();
458 		}
459 
460 		public int getSize()
461 		{
462 			return parts == null ? 0 : parts.length;
463 		}
464 
465 		public Object getSelectedItem()
466 		{
467 			return attachment == null ? null : attachment.getPart();
468 		}
469 
470 		public void setSelectedItem(Object anItem)
471 		{
472 			if (attachment != null)
473 				attachment.setPart((String) anItem);
474 		}
475 
476 		public void propertyChange( PropertyChangeEvent arg0 )
477 		{
478 			// delete our current one?
479 			if( arg0.getOldValue() == attachment && arg0.getNewValue() == null )
480 			{
481 				attachment = null;
482 				parts = null;
483 			}
484 		}
485 	}
486 }