1
2
3
4
5
6
7
8
9
10
11
12
13 package com.eviware.soapui;
14
15 import java.awt.BorderLayout;
16 import java.awt.Color;
17 import java.awt.Component;
18 import java.awt.Toolkit;
19 import java.awt.event.ActionEvent;
20 import java.awt.event.KeyEvent;
21 import java.awt.event.MouseAdapter;
22 import java.awt.event.MouseEvent;
23 import java.awt.event.WindowAdapter;
24 import java.awt.event.WindowEvent;
25 import java.beans.PropertyChangeEvent;
26 import java.beans.PropertyChangeListener;
27 import java.beans.PropertyVetoException;
28 import java.io.File;
29 import java.util.ArrayList;
30 import java.util.HashMap;
31 import java.util.Iterator;
32 import java.util.List;
33 import java.util.Map;
34
35 import javax.swing.AbstractAction;
36 import javax.swing.Action;
37 import javax.swing.BorderFactory;
38 import javax.swing.DefaultListModel;
39 import javax.swing.ImageIcon;
40 import javax.swing.JComponent;
41 import javax.swing.JDesktopPane;
42 import javax.swing.JFrame;
43 import javax.swing.JInternalFrame;
44 import javax.swing.JLabel;
45 import javax.swing.JList;
46 import javax.swing.JMenu;
47 import javax.swing.JMenuBar;
48 import javax.swing.JOptionPane;
49 import javax.swing.JPanel;
50 import javax.swing.JPopupMenu;
51 import javax.swing.JScrollPane;
52 import javax.swing.JSplitPane;
53 import javax.swing.JTabbedPane;
54 import javax.swing.JTextArea;
55 import javax.swing.JTree;
56 import javax.swing.KeyStroke;
57 import javax.swing.ListCellRenderer;
58 import javax.swing.SwingUtilities;
59 import javax.swing.ToolTipManager;
60 import javax.swing.UIManager;
61 import javax.swing.event.InternalFrameAdapter;
62 import javax.swing.event.InternalFrameEvent;
63 import javax.swing.event.MenuEvent;
64 import javax.swing.event.MenuListener;
65 import javax.swing.event.TreeSelectionEvent;
66 import javax.swing.event.TreeSelectionListener;
67 import javax.swing.plaf.ColorUIResource;
68 import javax.swing.tree.TreePath;
69 import javax.swing.tree.TreeSelectionModel;
70
71 import com.eviware.soapui.model.DesktopPanel;
72 import com.eviware.soapui.model.ModelItem;
73 import com.eviware.soapui.model.PanelBuilder;
74 import com.eviware.soapui.model.project.Project;
75 import com.eviware.soapui.model.tree.SoapUITreeModel;
76 import com.eviware.soapui.model.tree.SoapUITreeNode;
77 import com.eviware.soapui.model.tree.SoapUITreeNodeRenderer;
78 import com.eviware.soapui.model.tree.nodes.ProjectTreeNode;
79 import com.eviware.soapui.model.workspace.Workspace;
80 import com.eviware.soapui.model.workspace.WorkspaceFactory;
81 import com.eviware.soapui.support.UISupport;
82 import com.jgoodies.looks.plastic.PlasticXPLookAndFeel;
83 import com.jgoodies.looks.plastic.theme.SkyBluerTahoma;
84
85 /***
86 * Main SoapUI entry point.
87 *
88 * @author Ole.Matzura
89 *
90 * For version 0.6
91 * @todo improve error assertion reporting +
92 * @todo find/search/replace +
93 * @todo undo +
94 * @todo recreate request and keep values +
95 * @todo dont create optional elements +
96 * @todo option to create requests when importing +
97 * @todo show soapaction +
98 * @todo save response +
99 * @todo color-coding +
100 * @todo rapportera fel vid null-svar +
101 * @todo fixa bugg vid update interface +
102 * @todo xmlbeans2 +
103 * @todo httpclient rc3 +
104 * @todo refactor request panels +
105 * @todo refactor project/interface/testsuite listeners +
106 * @todo create properties table +
107 *
108 * For version 0.7
109 * @todo workspace in home folder +
110 * @todo allow renaming of operation names in tree +
111 * @todo add functionality for copying values from test response to following test request +
112 * @todo fix relative xsd imports when loading from file system +
113 * @todo fix cancelling of request when closing request window -> introduce DesktopPanel interface +
114 * @todo refactor panel creation / listener handling/release +
115 * @todo fix update of testcase window when adding test steps +
116 * @todo add delete-line action in xml-editor (Ctrl-D) +
117 * @todo add submit action to xml request editor (Ctrl Enter) +
118 * @todo add mousewheel support to xml editor +
119 * @todo add mousewheel + C support to xml editor (move cursor) +
120 * @todo fix revalidation problems +
121 * @todo add validation to xmleditors +
122 * @todo check localisation of schema errors +
123 * @todo add possibility to reload schema (neccessary?) +
124 * @todo fix cloning of assertions when cloning test steps +
125 * @todo ask for creation of optional elements when (re)creating new request +
126 * @todo add action to add existing namespaces to xpath in xpathassertion +
127 *
128 * For version 0.8
129 * @todo fix default values when creating requests +
130 * @todo bug-fixes
131 * - creation of namespace declarations creates multiple with same name +
132 * - check defintion update +
133 * - deletion of endpoint always deletes first +
134 * - deleted assertions result in error during save/exit? +
135 * - disable submit when missing endpoint +
136 * - clone request null-pointer +
137 * - fix value transfer element <> attribute +
138 * - fix cancelling of test requests +
139 * @todo create assertion events / listeners +
140 * @todo ask to add testcase if missing +
141 * @todo add alt-enter to response area +
142 * @todo allow url config of SchemaCompliance assertion +
143 * @todo add accelerators for common actions +
144 * @todo fix positions of dialogs +
145 * @todo add possibility to specify testsuite/testcase in maven-plugin +
146 * @todo refactoring: replaced SoapUIAction with standard swing Action +
147 * @todo refactoring: checked all JOptionPanes for correct title, etc. +
148 * @todo add filename-filters to filechoosers +
149 * @todo add shortcut for cancel request to editor +
150 *
151 * For version 0.9
152 * @todo initial class/code comments +
153 * @todo bug-fixes
154 * - fix cancelling of test runs +
155 * - fix removal of request test-steps when associated operations / interfaces are removed +
156 * - update of request-step status in testcase panel +
157 * - focus on find-field in find/replace dialog +
158 * - fix filters to not remove directories.. +
159 * - change wsdl file filter to *.wsdl +
160 * - disable declare in transfer panel when no transfer is selected +
161 * - declare in transfer panel declares target from target response (should be request) +
162 * - ask to cancel when closing running testcase +
163 * - fix pretty-printing of large xml-documents +
164 * - fix find and replace +
165 * - fix node insert error on multiple clone teststep +
166 * - fix log-messages from canceled requests +
167 * - disable replace-related options in find/replace if editor is not editable +
168 * @todo add possibility to move teststeps within testcase +
169 * @todo improve/disable disabling of request-editor +
170 * @todo add addAssertion button to testrequest panel +
171 * @todo add copy/pase actions to editor popup +
172 * @todo model-items tests
173 * @todo improve wsdl/xsd viewer +
174 * @todo improve line-number reporting in validations +
175 * @todo added shift-tab to move focus between request/response editors +
176 * @todo refactorings
177 * - SoapUIException +
178 * - UIFacade for JOptionPane + (partially)
179 *
180 * For version 1.0b
181 * @todo initial user documentation / samples +
182 * @todo bug-fixes +
183 * @todo more tests / testing! +
184 * @todo beta release +
185
186 * For version 1.0
187 * @todo official release +
188 *
189 * 1.1 Improvements
190 * @todo add possibility to transfer values from source request (instead of response)
191 * @todo add possibility to move teststeps to another testcase
192 * @todo workspace management
193 * @todo add reload-project!?
194 * @todo option to reload schemas on run testcase
195 */
196
197 public class SoapUI
198 {
199
200
201 private static final String DEFAULT_WORKSPACE_FILE = "default-soapui-workspace.xml";
202
203 private static SoapUI instance;
204
205 private JFrame frame;
206
207 private Map<ModelItem, JInternalFrame> modelItemToDesktopFrameMap = new HashMap<ModelItem, JInternalFrame>();
208 private Map<ModelItem, DesktopPanel> modelItemToDesktopPanelMap = new HashMap<ModelItem, DesktopPanel>();
209
210 private Map<JInternalFrame, ModelItem> contentPanelToModelItemMap = new HashMap<JInternalFrame, ModelItem>();
211
212 private JTextArea logArea;
213
214 private JDesktopPane desktopPane = new JDesktopPane();
215
216 private JTree mainTree = new JTree();
217
218 private SoapUITreeModel treeModel;
219
220 private Workspace workspace;
221
222 private static List<String> logCache = new ArrayList<String>();
223 private static int openFrameCount = 0;
224 private static final int xOffset = 30, yOffset = 30;
225
226 private JMenu windowMenu;
227
228 private JMenu fileMenu;
229
230 private JMenuBar menuBar;
231
232 private InternalDesktopFrameListener internalFrameListener = new InternalDesktopFrameListener();
233
234 private JList desktopPanelsList;
235
236 private DefaultListModel desktopPanels;
237
238 private ModelItemPropertyChangeListener modelItemPropertyListener = new ModelItemPropertyChangeListener();
239
240 private JSplitPane contentSplit;
241
242 private JPanel overviewPanel;
243
244 public final static String SOAPUI_VERSION = "1.0";
245
246 private JTabbedPane detailTabs;
247
248
249
250
251 static
252 {
253 try
254 {
255 PlasticXPLookAndFeel.setMyCurrentTheme(new SoapUITheme());
256 PlasticXPLookAndFeel.setTabStyle("Metal");
257
258 UIManager.setLookAndFeel(new PlasticXPLookAndFeel());
259 }
260
261 catch (Throwable e)
262 {
263 System.err.println( "Error initializing PlasticXPLookAndFeel; " + e.getMessage() );
264 }
265 }
266
267
268
269 public SoapUI()
270 {
271 ToolTipManager.sharedInstance().setInitialDelay( 200 );
272
273 frame = new JFrame("SoapUI " + SOAPUI_VERSION);
274 frame.addWindowListener(new WindowAdapter()
275 {
276 public void windowClosing(WindowEvent e)
277 {
278 if( JOptionPane.showConfirmDialog( frame, "Exit SoapUI?", "Question", JOptionPane.OK_CANCEL_OPTION )
279 != JOptionPane.OK_OPTION )
280 return;
281
282 workspace.onClose();
283 frame.dispose();
284 }
285
286 public void windowClosed(WindowEvent e)
287 {
288 System.exit( 0 );
289 }
290
291 });
292
293 UISupport.setMainFrame( frame );
294 instance = this;
295 }
296
297 private void buildUI()
298 {
299 treeModel = new SoapUITreeModel(workspace);
300 mainTree.setModel(treeModel);
301 mainTree.setRootVisible(true);
302 mainTree.setExpandsSelectedPaths(true);
303 mainTree.setToggleClickCount( 0 );
304 mainTree.addMouseListener(new TreeMouseListener());
305 mainTree.addTreeSelectionListener(new InternalTreeSelectionListener());
306 mainTree.setCellRenderer( new SoapUITreeNodeRenderer() );
307
308 ToolTipManager.sharedInstance().registerComponent(mainTree);
309
310 JSplitPane splitPane = UISupport.createHorizontalSplit( buildMainPanel(), buildContentPanel() );
311
312 frame.setJMenuBar(buildMainMenu());
313 frame.getContentPane().add(splitPane, BorderLayout.CENTER);
314 frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
315 frame.setSize(900, 700);
316
317 splitPane.setDividerLocation(250);
318 }
319
320 public static SoapUI getInstance()
321 {
322 return instance;
323 }
324
325 private JMenuBar buildMainMenu()
326 {
327 menuBar = new JMenuBar();
328 fileMenu = new JMenu("File");
329 fileMenu.setMnemonic( KeyEvent.VK_F );
330
331 Action[] actions = workspace.getActions();
332 for (int i = 0; i < actions.length; i++)
333 {
334 fileMenu.add( actions[i] );
335 }
336
337 fileMenu.addSeparator();
338 fileMenu.add( new SaveAction() );
339
340 fileMenu.addSeparator();
341 fileMenu.add( new ExitAction() );
342
343 menuBar.add(fileMenu);
344
345 windowMenu = new JMenu( "Window");
346 windowMenu.setMnemonic( KeyEvent.VK_W );
347 windowMenu.add(new CloseCurrentAction());
348 windowMenu.add(new CloseAllAction());
349 windowMenu.add(new CloseOtherAction());
350 windowMenu.addMenuListener( new MenuListener()
351 {
352 public void menuSelected(MenuEvent e)
353 {
354 while( windowMenu.getMenuComponentCount() > 3 )
355 windowMenu.remove( 3 );
356
357 if( contentPanelToModelItemMap.size() == 0 ) return;
358 windowMenu.addSeparator();
359 Iterator<JInternalFrame> i = contentPanelToModelItemMap.keySet().iterator();
360 while( i.hasNext() )
361 {
362 windowMenu.add( new PaneSelectionAction( i.next() ));
363 }
364 }
365
366 public void menuDeselected(MenuEvent e)
367 {
368 }
369
370 public void menuCanceled(MenuEvent e)
371 {
372 }});
373
374 menuBar.add(windowMenu);
375
376
377 return menuBar;
378 }
379
380 public JFrame getFrame()
381 {
382 return frame;
383 }
384
385 private JComponent buildMainPanel()
386 {
387 JSplitPane splitPane = UISupport.createVerticalSplit();
388 JPanel mainPanel = new JPanel(new BorderLayout());
389
390 mainTree.setBorder(null);
391 mainTree.getSelectionModel().setSelectionMode( TreeSelectionModel.SINGLE_TREE_SELECTION );
392 splitPane.setBorder(BorderFactory.createEmptyBorder(2, 2, 2, 2));
393
394 splitPane.setTopComponent(new JScrollPane(mainTree));
395 splitPane.setBottomComponent(buildOverviewPanel());
396 splitPane.setDividerLocation( 500 );
397 splitPane.setResizeWeight( 0.6 );
398 return splitPane;
399 }
400
401 private Component buildOverviewPanel()
402 {
403 detailTabs = new JTabbedPane( JTabbedPane.BOTTOM );
404 desktopPanels = new DefaultListModel();
405 desktopPanelsList = new JList( desktopPanels );
406 desktopPanelsList.setCellRenderer( new DesktopItemsCellRenderer() );
407 desktopPanelsList.setToolTipText( "Open windows" );
408 desktopPanelsList.addMouseListener( new MouseAdapter() {
409
410 public void mouseClicked(MouseEvent e)
411 {
412 if( e.getClickCount() < 2 ) return;
413 ModelItem modelItem = (ModelItem) desktopPanelsList.getSelectedValue();
414 if( modelItem == null ) return;
415
416 showTab( modelItem );
417 }} );
418
419 JPanel panel = new JPanel( new BorderLayout() );
420 panel.setBackground( Color.LIGHT_GRAY );
421 panel.add( detailTabs, BorderLayout.CENTER );
422 detailTabs.addTab( "Windows", new JScrollPane( desktopPanelsList ));
423
424 overviewPanel = new JPanel( new BorderLayout() );
425 detailTabs.addTab( "Details", overviewPanel );
426
427 return panel;
428 }
429
430 private void setOverviewPanel(Component panel)
431 {
432 if( overviewPanel.getComponentCount() == 0 && panel == null )
433 return;
434
435 overviewPanel.removeAll();
436 if( panel != null )
437 overviewPanel.add( panel, BorderLayout.CENTER );
438 overviewPanel.revalidate();
439 overviewPanel.repaint();
440 }
441
442 private Component buildContentPanel()
443 {
444 contentSplit = UISupport.createVerticalSplit();
445 JPanel contentPanel = new JPanel(new BorderLayout());
446
447 contentSplit.setBorder(BorderFactory.createEmptyBorder(2, 2, 2, 2));
448
449 contentSplit.setTopComponent(buildTabbedPanel());
450 contentSplit.setBottomComponent(buildLogPanel());
451 contentSplit.setDividerLocation(550);
452 contentSplit.setResizeWeight( 0.9 );
453 return contentSplit;
454 }
455
456 private class PaneSelectionAction extends AbstractAction
457 {
458 private final JInternalFrame frame2;
459
460 public PaneSelectionAction(JInternalFrame frame)
461 {
462 super( frame.getTitle() );
463 frame2 = frame;
464 }
465
466 public void actionPerformed(ActionEvent e)
467 {
468 showTab( contentPanelToModelItemMap.get( frame2 ));
469 }}
470
471 private Component buildTabbedPanel()
472 {
473 JScrollPane scrollPane = new JScrollPane( desktopPane );
474 return scrollPane;
475 }
476
477 private Component buildLogPanel()
478 {
479 logArea = new JTextArea();
480 logArea.setEditable(false);
481 logArea.setToolTipText("SoapUI Log");
482
483 for (String message : logCache)
484 {
485 logArea.setText( logArea.getText() + message + "\n" );
486 }
487
488 JPanel panel = new JPanel(new BorderLayout());
489 panel.setBorder(BorderFactory.createEmptyBorder(3, 3, 3, 3));
490 panel.add(new JScrollPane(logArea), BorderLayout.CENTER);
491 return panel;
492 }
493
494
495
496 public synchronized void log(final String msg)
497 {
498 if( instance == null || instance.logArea == null )
499 {
500 logCache.add( msg );
501 return;
502 }
503
504 if (SwingUtilities.isEventDispatchThread())
505 {
506 instance.logArea.setText(instance.logArea.getText() + msg + "\r\n");
507 }
508 else
509 {
510 SwingUtilities.invokeLater(new Runnable()
511 {
512 public void run()
513 {
514 instance.logArea.setText(instance.logArea.getText() + msg + "\r\n");
515 }
516 });
517 }
518 }
519
520
521
522 private static class SoapUITheme extends SkyBluerTahoma
523 {
524 public ColorUIResource getControl()
525 {
526 return new ColorUIResource(new Color(238, 237, 237));
527 }
528 }
529
530
531
532 public static void main(String[] args) throws Exception
533 {
534 SoapUI soapUI = new SoapUI();
535 Workspace workspace = null;
536
537 if (args.length > 0)
538 workspace = WorkspaceFactory.getInstance().openWorkspace(args);
539 else
540 workspace = WorkspaceFactory.getInstance().openWorkspace(new String[] { System.getProperty("user.home") +
541 File.separatorChar + DEFAULT_WORKSPACE_FILE });
542
543 soapUI.show(workspace);
544 }
545
546 private void show(Workspace workspace)
547 {
548 this.workspace = workspace;
549 buildUI();
550
551 frame.setVisible(true);
552 }
553
554 public class TreeMouseListener extends MouseAdapter
555 {
556 public void mouseClicked(MouseEvent e)
557 {
558 if (e.isPopupTrigger())
559 showPopup(e);
560 else if (e.getClickCount() < 2)
561 return;
562 if (mainTree.getSelectionCount() != 1)
563 return;
564
565 TreePath path = mainTree.getSelectionPath();
566 SoapUITreeNode node = (SoapUITreeNode) path.getLastPathComponent();
567
568 showTab( node.getModelItem() );
569 }
570
571 public void mousePressed(MouseEvent e)
572 {
573 if (e.isPopupTrigger())
574 showPopup(e);
575 }
576
577 public void mouseReleased(MouseEvent e)
578 {
579 if (e.isPopupTrigger())
580 showPopup(e);
581 }
582
583 private void showPopup(MouseEvent e)
584 {
585 TreePath path = mainTree.getPathForLocation((int) e.getPoint().getX(), (int) e.getPoint().getY());
586 if (path == null)
587 return;
588 SoapUITreeNode node = (SoapUITreeNode) path.getLastPathComponent();
589
590 JPopupMenu popupMenu = node.getPopup();
591 if (popupMenu == null)
592 return;
593
594 mainTree.setSelectionPath(path);
595
596 popupMenu.show(mainTree, e.getX(), e.getY());
597 }
598 }
599
600 public class CloseCurrentAction extends AbstractAction
601 {
602 public CloseCurrentAction()
603 {
604 super("Close Current");
605 putValue(Action.SHORT_DESCRIPTION, "Closes the current window");
606 putValue( Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke( KeyEvent.VK_R, KeyEvent.CTRL_MASK ));
607
608 }
609
610 public void actionPerformed(ActionEvent e)
611 {
612 JInternalFrame frame = desktopPane.getSelectedFrame();
613 if( frame != null )
614 closeTab( contentPanelToModelItemMap.get(frame));
615 }
616 }
617
618 public class CloseOtherAction extends AbstractAction
619 {
620 public CloseOtherAction()
621 {
622 super("Close others");
623 putValue(Action.SHORT_DESCRIPTION, "Closes all windows except the current one");
624 putValue( Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke( KeyEvent.VK_O, KeyEvent.CTRL_MASK ));
625
626 }
627
628 public void actionPerformed(ActionEvent e)
629 {
630 JInternalFrame frame = desktopPane.getSelectedFrame();
631 if( frame == null )
632 return;
633
634 Iterator<JInternalFrame> i = contentPanelToModelItemMap.keySet().iterator();
635 while( i.hasNext() )
636 {
637 JInternalFrame f = i.next();
638 if( f != frame )
639 {
640 closeTab( contentPanelToModelItemMap.get( f ) );
641 i = contentPanelToModelItemMap.keySet().iterator();
642 }
643 }
644 }
645 }
646
647 public class CloseAllAction extends AbstractAction
648 {
649 public CloseAllAction()
650 {
651 super("Close all");
652 putValue( Action.SHORT_DESCRIPTION, "Closes all windows");
653 putValue( Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke( KeyEvent.VK_L, KeyEvent.CTRL_MASK ));
654 }
655
656 public void actionPerformed(ActionEvent e)
657 {
658 while( contentPanelToModelItemMap.size() > 0 )
659 {
660 Iterator<JInternalFrame> i = contentPanelToModelItemMap.keySet().iterator();
661 try
662 {
663 i.next().setClosed( true );
664 }
665 catch (PropertyVetoException e1)
666 {
667 e1.printStackTrace();
668 }
669 }
670
671 contentPanelToModelItemMap.clear();
672 modelItemToDesktopFrameMap.clear();
673 modelItemToDesktopPanelMap.clear();
674 }
675 }
676
677 public class InternalTreeSelectionListener implements TreeSelectionListener
678 {
679 public void valueChanged(TreeSelectionEvent e)
680 {
681 Object obj = e.getPath().getLastPathComponent();
682 if (obj instanceof SoapUITreeNode)
683 {
684 SoapUITreeNode treeNode = (SoapUITreeNode) obj;
685 setOverviewPanel(treeNode.getOverviewPanel());
686 }
687 }
688 }
689
690 public Workspace getWorkspace()
691 {
692 return workspace;
693 }
694
695 public boolean hasTab( ModelItem modelItem )
696 {
697 return modelItemToDesktopFrameMap.containsKey( modelItem );
698 }
699
700 public JInternalFrame showTab( ModelItem modelItem )
701 {
702 PanelBuilder panelBuilder = modelItem.getPanelBuilder();
703 if (modelItemToDesktopFrameMap.containsKey(modelItem))
704 {
705 JInternalFrame frame = modelItemToDesktopFrameMap.get(modelItem);
706 try
707 {
708 desktopPane.getDesktopManager().deiconifyFrame( frame );
709 frame.setSelected( true );
710 frame.moveToFront();
711 return frame;
712 }
713 catch (PropertyVetoException e)
714 {
715 e.printStackTrace();
716 }
717 }
718 else if (panelBuilder != null && panelBuilder.canBuildDesktopPanel())
719 {
720 String title = panelBuilder.getDesktopPanelTitle();
721 DesktopPanel desktopPanel = panelBuilder.buildDesktopPanel();
722 JComponent panel = desktopPanel.getComponent();
723 panel.setOpaque( true );
724
725 JInternalFrame frame = createContentFrame(title, panel);
726
727 desktopPane.add( frame );
728 try
729 {
730 frame.setSelected( true );
731 }
732 catch (PropertyVetoException e)
733 {
734 e.printStackTrace();
735 }
736
737 modelItemToDesktopFrameMap.put(modelItem, frame);
738 modelItemToDesktopPanelMap.put( modelItem, desktopPanel );
739 contentPanelToModelItemMap.put(frame, modelItem);
740
741 desktopPanels.addElement( modelItem );
742 desktopPanelsList.setSelectedValue( modelItem, false );
743 modelItem.addPropertyChangeListener( modelItemPropertyListener );
744
745 return frame;
746 }
747 else Toolkit.getDefaultToolkit().beep();
748
749 return null;
750 }
751
752 private JInternalFrame createContentFrame(String title, JComponent panel)
753 {
754 JInternalFrame frame = new JInternalFrame(title, true, true, true, true );
755 frame.addInternalFrameListener( internalFrameListener );
756 frame.setContentPane( panel );
757 frame.setSize( panel.getPreferredSize() );
758 frame.setVisible( true );
759 frame.setDefaultCloseOperation( JInternalFrame.DO_NOTHING_ON_CLOSE );
760 frame.setLocation(xOffset*(openFrameCount%10), yOffset*(openFrameCount%10));
761 frame.setBorder( BorderFactory.createCompoundBorder(
762 BorderFactory.createRaisedBevelBorder(), BorderFactory.createEmptyBorder( 2, 2, 2, 2 )));
763 openFrameCount++;
764 return frame;
765 }
766
767 public void closeTab(ModelItem modelItem)
768 {
769 if (modelItemToDesktopFrameMap.containsKey(modelItem))
770 {
771 JInternalFrame frame = modelItemToDesktopFrameMap.get(modelItem);
772 frame.doDefaultCloseAction();
773 }
774 }
775
776 public Project getCurrentProject()
777 {
778 TreePath path = mainTree.getSelectionPath();
779 Object node = (Object) path.getLastPathComponent();
780 while (node != null && !(node instanceof ProjectTreeNode))
781 {
782 path = path.getParentPath();
783 node = (path == null ? null : path.getLastPathComponent());
784 }
785
786 if (node == null)
787 return null;
788
789 return ((ProjectTreeNode) node).getProject();
790 }
791
792 /*** Returns an ImageIcon, or null if the path was invalid. */
793 public static ImageIcon createImageIcon(String path) {
794 java.net.URL imgURL = SoapUI.class.getResource(path);
795 if (imgURL != null) {
796 return new ImageIcon(imgURL);
797 } else {
798 System.err.println("Couldn't find icon file: " + path);
799 return null;
800 }
801 }
802
803 private class ExitAction extends AbstractAction
804 {
805 public ExitAction()
806 {
807 super( "Exit" );
808 putValue( Action.SHORT_DESCRIPTION, "Saves all projects and exits SoapUI" );
809 putValue( Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke( KeyEvent.VK_Q, KeyEvent.CTRL_MASK ));
810 }
811
812 public void actionPerformed(ActionEvent e)
813 {
814 frame.dispatchEvent( new WindowEvent( frame, WindowEvent.WINDOW_CLOSING ));
815 }
816 }
817
818 private class SaveAction extends AbstractAction
819 {
820 public SaveAction()
821 {
822 super( "Save all" );
823 putValue( Action.SHORT_DESCRIPTION, "Saves all projects" );
824 putValue( Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke( KeyEvent.VK_S, KeyEvent.CTRL_MASK ));
825 }
826
827 public void actionPerformed(ActionEvent e)
828 {
829 workspace.save();
830 }
831 }
832
833
834 private class InternalDesktopFrameListener extends InternalFrameAdapter
835 {
836 public void internalFrameClosing(InternalFrameEvent e)
837 {
838 ModelItem modelItem = contentPanelToModelItemMap.get( e.getInternalFrame() );
839 DesktopPanel desktopPanel = modelItemToDesktopPanelMap.get( modelItem );
840 if( !desktopPanel.onClose() )
841 {
842 return;
843 }
844
845 modelItemToDesktopFrameMap.remove( modelItem );
846 modelItemToDesktopPanelMap.remove( modelItem );
847 contentPanelToModelItemMap.remove( e.getInternalFrame() );
848 desktopPanels.removeElement( modelItem );
849
850 e.getInternalFrame().dispose();
851 }
852
853 public void internalFrameActivated(InternalFrameEvent e)
854 {
855 ModelItem modelItem = contentPanelToModelItemMap.get( e.getInternalFrame() );
856 if( modelItem != null )
857 {
858 desktopPanelsList.setSelectedValue( modelItem, false );
859 selectModelItem( modelItem );
860 }
861 }
862 }
863
864 private class DesktopItemsCellRenderer extends JLabel implements ListCellRenderer
865 {
866 public Component getListCellRendererComponent(
867 JList list,
868 Object value,
869 int index,
870 boolean isSelected,
871 boolean cellHasFocus)
872 {
873 ModelItem modelItem = (ModelItem) value;
874
875 String title = modelItemToDesktopFrameMap.get( modelItem ).getTitle();
876 setText( title );
877
878 setToolTipText( title );
879 setIcon( modelItem.getIcon() );
880
881 if (isSelected)
882 {
883 setBackground(list.getSelectionBackground());
884 setForeground(list.getSelectionForeground());
885 }
886 else
887 {
888 setBackground(list.getBackground());
889 setForeground(list.getForeground());
890 }
891
892 setEnabled(list.isEnabled());
893 setFont(list.getFont());
894 setOpaque(true);
895
896 return this;
897 }
898 }
899
900 private class ModelItemPropertyChangeListener implements PropertyChangeListener
901 {
902 public void propertyChange(PropertyChangeEvent evt)
903 {
904 ModelItem modelItem = (ModelItem) evt.getSource();
905 int ix = desktopPanels.indexOf( modelItem );
906 if( ix >= 0 )
907 desktopPanels.set( ix, modelItem );
908 }}
909
910 public void selectModelItem(ModelItem modelItem)
911 {
912 TreePath path = treeModel.getPath( modelItem );
913 mainTree.setSelectionPath( path );
914 mainTree.scrollPathToVisible( path );
915 }
916
917 public SoapUITreeModel getTreeModel()
918 {
919 return treeModel;
920 }
921
922 }