View Javadoc

1   /*
2    *  soapUI, copyright (C) 2004-2010 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, "."
268 								+ ContentTypeHandler.getExtensionForContentType( attachment.getContentType() ) );
269 						exportAttachment( tempFile, attachment, false );
270 					}
271 					catch( Exception e1 )
272 					{
273 						UISupport.showErrorMessage( e1 );
274 					}
275 				}
276 				else
277 				{
278 					Tools.openURL( attachment.getUrl() );
279 				}
280 			}
281 		} );
282 	}
283 
284 	protected void exportBtnActionPerformed( ActionEvent evt )
285 	{
286 		File file = UISupport.getFileDialogs().saveAs( this, "Export Attachment.." );
287 		while( file != null && file.exists()
288 				&& !UISupport.confirm( "File " + file.getName() + " exists, overwrite?", "Export Attachment" ) )
289 		{
290 			file = UISupport.getFileDialogs().saveAs( this, "Export Attachment.." );
291 		}
292 
293 		if( file != null )
294 		{
295 			Attachment attachment = tableModel.getAttachmentAt( fileTable.getSelectedRow() );
296 			try
297 			{
298 				exportAttachment( file, attachment, true );
299 			}
300 			catch( Exception e )
301 			{
302 				UISupport.showErrorMessage( e );
303 			}
304 		}
305 	}
306 
307 	private void exportAttachment( File file, Attachment attachment, boolean showOpenQuery )
308 			throws FileNotFoundException, IOException, Exception, MalformedURLException
309 	{
310 		FileOutputStream out = new FileOutputStream( file );
311 
312 		long total = Tools.writeAll( out, attachment.getInputStream() );
313 		out.close();
314 		if( !showOpenQuery
315 				|| UISupport.confirm( "Written [" + total + "] bytes to " + file.getName() + ", open in browser?",
316 						"Saved File" ) )
317 		{
318 			Tools.openURL( file.toURI().toURL().toString() );
319 		}
320 	}
321 
322 	protected void reloadBtnActionPerformed( ActionEvent evt )
323 	{
324 		int selectedRow = fileTable.getSelectedRow();
325 		if( selectedRow == -1 )
326 			return;
327 
328 		WsdlAttachment attachment = ( WsdlAttachment )tableModel.getAttachmentAt( selectedRow );
329 		if( attachment == null )
330 			return;
331 
332 		File file = UISupport.getFileDialogs().open( this, "Reload Attachment..", "*", "Any File", attachment.getUrl() );
333 		if( file != null )
334 		{
335 			Boolean retval = UISupport.confirmOrCancel( "Cache attachment in request?", "Reload Attachment" );
336 			if( retval == null )
337 				return;
338 
339 			try
340 			{
341 				attachment.reload( file, retval );
342 				tableModel.fireTableRowsUpdated( selectedRow, selectedRow );
343 			}
344 			catch( IOException e )
345 			{
346 				UISupport.showErrorMessage( e );
347 			}
348 		}
349 	}
350 
351 	private void addFileBtnActionPerformed( java.awt.event.ActionEvent evt )
352 	{// GEN-FIRST:event_addFileBtnActionPerformed
353 		if( fc == null )
354 			fc = new JFileChooser();
355 
356 		String root = PathUtils.getExpandedResourceRoot( container.getModelItem() );
357 		if( StringUtils.hasContent( root ) )
358 			fc.setCurrentDirectory( new File( root ) );
359 
360 		int returnVal = fc.showOpenDialog( this );
361 
362 		if( returnVal == JFileChooser.APPROVE_OPTION )
363 		{
364 			File file = fc.getSelectedFile();
365 			Boolean retval = UISupport.confirmOrCancel( "Cache attachment in request?", "Add Attachment" );
366 			if( retval == null )
367 				return;
368 			try
369 			{
370 				tableModel.addFile( file, retval );
371 			}
372 			catch( IOException e )
373 			{
374 				UISupport.showErrorMessage( e );
375 			}
376 		}
377 		else
378 		{
379 			System.out.println( "Open command cancelled by user." );
380 		}
381 	}// GEN-LAST:event_addFileBtnActionPerformed
382 
383 	private void removeBtnActionPerformed( java.awt.event.ActionEvent evt )
384 	{// GEN-FIRST:event_removeBtnActionPerformed
385 		if( UISupport.confirm( "Remove selected attachments?", "Remove Attachments" ) )
386 			tableModel.removeAttachment( fileTable.getSelectedRows() );
387 	}// GEN-LAST:event_removeBtnActionPerformed
388 
389 	// Variables declaration - do not modify//GEN-BEGIN:variables
390 	private javax.swing.JButton addFileBtn;
391 	private JTable fileTable;
392 	private JXToolBar jPanel1;
393 	private javax.swing.JScrollPane jScrollPane1;
394 	private javax.swing.JButton removeBtn;
395 	private AttachmentPartCellEditor attachmentPartCellEditor;
396 
397 	// End of variables declaration//GEN-END:variables
398 
399 	private class AttachmentPartCellEditor extends DefaultCellEditor
400 	{
401 		public AttachmentPartCellEditor()
402 		{
403 			super( new JComboBox( new PartsComboBoxModel() ) );
404 		}
405 
406 		public void release()
407 		{
408 			( ( PartsComboBoxModel )( ( JComboBox )editorComponent ).getModel() ).release();
409 		}
410 
411 		public Component getTableCellEditorComponent( JTable table, Object value, boolean isSelected, int row, int column )
412 		{
413 			PartsComboBoxModel model = ( ( PartsComboBoxModel )( ( JComboBox )editorComponent ).getModel() );
414 			( ( JComboBox )editorComponent ).setModel( model.init( tableModel.getAttachmentAt( row ) ) );
415 
416 			return super.getTableCellEditorComponent( table, value, isSelected, row, column );
417 		}
418 	}
419 
420 	private final class PartsComboBoxModel extends AbstractListModel implements ComboBoxModel, PropertyChangeListener
421 	{
422 		private Attachment attachment;
423 		private AttachmentPart[] parts;
424 
425 		public PartsComboBoxModel()
426 		{
427 			container.addAttachmentsChangeListener( this );
428 		}
429 
430 		public void release()
431 		{
432 			container.removeAttachmentsChangeListener( this );
433 		}
434 
435 		public PartsComboBoxModel init( Attachment attachment )
436 		{
437 			this.attachment = attachment;
438 
439 			int previousPartsCount = parts == null ? 0 : parts.length;
440 
441 			parts = container.getDefinedAttachmentParts();
442 			if( previousPartsCount < parts.length )
443 			{
444 				fireIntervalAdded( this, previousPartsCount, parts.length );
445 			}
446 			else if( previousPartsCount > parts.length )
447 			{
448 				fireIntervalRemoved( this, parts.length - 1, previousPartsCount );
449 			}
450 
451 			fireContentsChanged( this, 0, parts.length - 1 );
452 
453 			return this;
454 		}
455 
456 		public Object getElementAt( int index )
457 		{
458 			return parts == null ? null : parts[index].getName();
459 		}
460 
461 		public int getSize()
462 		{
463 			return parts == null ? 0 : parts.length;
464 		}
465 
466 		public Object getSelectedItem()
467 		{
468 			return attachment == null ? null : attachment.getPart();
469 		}
470 
471 		public void setSelectedItem( Object anItem )
472 		{
473 			if( attachment != null )
474 				attachment.setPart( ( String )anItem );
475 		}
476 
477 		public void propertyChange( PropertyChangeEvent arg0 )
478 		{
479 			// delete our current one?
480 			if( arg0.getOldValue() == attachment && arg0.getNewValue() == null )
481 			{
482 				attachment = null;
483 				parts = null;
484 			}
485 		}
486 	}
487 }