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