View Javadoc

1   /*
2    *  soapUI, copyright (C) 2004-2007 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;
14  
15  import java.awt.BorderLayout;
16  import java.awt.Component;
17  import java.awt.Dimension;
18  import java.awt.dnd.DnDConstants;
19  import java.awt.dnd.DragSource;
20  import java.awt.event.ActionEvent;
21  import java.awt.event.KeyEvent;
22  import java.awt.event.WindowAdapter;
23  import java.awt.event.WindowEvent;
24  import java.io.File;
25  import java.net.URI;
26  import java.net.URISyntaxException;
27  import java.util.ArrayList;
28  import java.util.Collections;
29  import java.util.List;
30  import java.util.Properties;
31  import java.util.Timer;
32  import java.util.TimerTask;
33  
34  import javax.swing.AbstractAction;
35  import javax.swing.Action;
36  import javax.swing.BorderFactory;
37  import javax.swing.JComponent;
38  import javax.swing.JFrame;
39  import javax.swing.JMenu;
40  import javax.swing.JMenuBar;
41  import javax.swing.JMenuItem;
42  import javax.swing.JPanel;
43  import javax.swing.JTabbedPane;
44  import javax.swing.JTree;
45  import javax.swing.SwingConstants;
46  import javax.swing.SwingUtilities;
47  import javax.swing.ToolTipManager;
48  
49  import org.apache.log4j.Level;
50  import org.apache.log4j.Logger;
51  
52  import com.eviware.soapui.actions.SaveAllProjectsAction;
53  import com.eviware.soapui.actions.SoapUIPreferencesAction;
54  import com.eviware.soapui.actions.SwitchDesktopPanelAction;
55  import com.eviware.soapui.impl.WorkspaceImpl;
56  import com.eviware.soapui.impl.actions.ImportWsdlProjectAction;
57  import com.eviware.soapui.impl.actions.NewWsdlProjectAction;
58  import com.eviware.soapui.impl.wsdl.actions.iface.tools.axis1.Axis1XWSDL2JavaAction;
59  import com.eviware.soapui.impl.wsdl.actions.iface.tools.axis2.Axis2WSDL2CodeAction;
60  import com.eviware.soapui.impl.wsdl.actions.iface.tools.cxf.CXFAction;
61  import com.eviware.soapui.impl.wsdl.actions.iface.tools.dotnet.DotNetWsdlAction;
62  import com.eviware.soapui.impl.wsdl.actions.iface.tools.gsoap.GSoapAction;
63  import com.eviware.soapui.impl.wsdl.actions.iface.tools.jaxb.JaxbXjcAction;
64  import com.eviware.soapui.impl.wsdl.actions.iface.tools.jbossws.JBossWSConsumeAction;
65  import com.eviware.soapui.impl.wsdl.actions.iface.tools.jbossws.WSToolsWsdl2JavaAction;
66  import com.eviware.soapui.impl.wsdl.actions.iface.tools.oracle.OracleWsaGenProxyAction;
67  import com.eviware.soapui.impl.wsdl.actions.iface.tools.tcpmon.TcpMonAction;
68  import com.eviware.soapui.impl.wsdl.actions.iface.tools.wscompile.WSCompileAction;
69  import com.eviware.soapui.impl.wsdl.actions.iface.tools.wsimport.WSImportAction;
70  import com.eviware.soapui.impl.wsdl.actions.iface.tools.xfire.XFireAction;
71  import com.eviware.soapui.impl.wsdl.actions.iface.tools.xmlbeans.XmlBeans2Action;
72  import com.eviware.soapui.impl.wsdl.actions.support.OpenUrlAction;
73  import com.eviware.soapui.impl.wsdl.actions.support.ShowOnlineHelpAction;
74  import com.eviware.soapui.impl.wsdl.panels.teststeps.support.PropertyHolderTable;
75  import com.eviware.soapui.impl.wsdl.support.HelpUrls;
76  import com.eviware.soapui.model.ModelItem;
77  import com.eviware.soapui.model.PanelBuilder;
78  import com.eviware.soapui.model.TestPropertyHolder;
79  import com.eviware.soapui.model.propertyexpansion.PropertyExpansionUtils;
80  import com.eviware.soapui.model.settings.Settings;
81  import com.eviware.soapui.model.settings.SettingsListener;
82  import com.eviware.soapui.model.tree.SoapUITreeNode;
83  import com.eviware.soapui.model.util.PanelBuilderRegistry;
84  import com.eviware.soapui.model.workspace.Workspace;
85  import com.eviware.soapui.model.workspace.WorkspaceFactory;
86  import com.eviware.soapui.monitor.MockEngine;
87  import com.eviware.soapui.monitor.TestMonitor;
88  import com.eviware.soapui.settings.UISettings;
89  import com.eviware.soapui.support.UISupport;
90  import com.eviware.soapui.support.action.SoapUIActionRegistry;
91  import com.eviware.soapui.support.action.swing.ActionList;
92  import com.eviware.soapui.support.action.swing.ActionListBuilder;
93  import com.eviware.soapui.support.action.swing.ActionSupport;
94  import com.eviware.soapui.support.action.swing.SwingActionDelegate;
95  import com.eviware.soapui.support.components.JComponentInspector;
96  import com.eviware.soapui.support.components.JInspectorPanel;
97  import com.eviware.soapui.support.components.JPropertiesTable;
98  import com.eviware.soapui.support.components.JXToolBar;
99  import com.eviware.soapui.support.dnd.DropType;
100 import com.eviware.soapui.support.dnd.NavigatorDragAndDropable;
101 import com.eviware.soapui.support.dnd.SoapUIDragAndDropHandler;
102 import com.eviware.soapui.support.listener.SoapUIListenerRegistry;
103 import com.eviware.soapui.support.log.InspectorLog4JMonitor;
104 import com.eviware.soapui.support.log.JLogList;
105 import com.eviware.soapui.support.log.Log4JMonitor;
106 import com.eviware.soapui.support.log.LogDisablingTestMonitorListener;
107 import com.eviware.soapui.support.monitor.MonitorPanel;
108 import com.eviware.soapui.support.monitor.RuntimeMemoryMonitorSource;
109 import com.eviware.soapui.ui.JDesktopPanelsList;
110 import com.eviware.soapui.ui.Navigator;
111 import com.eviware.soapui.ui.NavigatorListener;
112 import com.eviware.soapui.ui.desktop.DesktopPanel;
113 import com.eviware.soapui.ui.desktop.DesktopRegistry;
114 import com.eviware.soapui.ui.desktop.SoapUIDesktop;
115 import com.eviware.soapui.ui.desktop.standalone.StandaloneDesktop;
116 import com.eviware.soapui.ui.support.DesktopListenerAdapter;
117 import com.jgoodies.looks.HeaderStyle;
118 import com.jgoodies.looks.Options;
119 
120 /***
121  * Main SoapUI entry point.
122  * 
123  */
124 
125 public class SoapUI
126 {
127 	public static final String DEFAULT_DESKTOP = "Default";
128 	public static final String CURRENT_SOAPUI_WORKSPACE = SoapUI.class.getName() + "@workspace";
129 	public final static Logger log = Logger.getLogger( SoapUI.class );
130 	public final static String SOAPUI_VERSION = "2.0.1";
131 	public static final String DEFAULT_WORKSPACE_FILE = "default-soapui-workspace.xml";
132 	public static final String SOAPUI_SPLASH_GIF = "soapui-splash.gif";
133 	private static final int DEFAULT_DESKTOP_ACTIONS_COUNT = 3;
134 
135 	// ------------------------------ FIELDS ------------------------------
136 
137 //	private static SoapUI instance;
138 	private static List<Object> logCache = new ArrayList<Object>();
139 	
140 	private static SoapUICore soapUICore;
141 	private static JFrame frame;
142 
143 	private static Navigator navigator;
144 	private static SoapUIDesktop desktop;
145 	private static Workspace workspace;
146 	private static Log4JMonitor logMonitor;
147 	private static Logger errorLog = Logger.getLogger( "soapui.errorlog" );
148 	private static boolean isStandalone;
149 	private static TestMonitor testMonitor;
150 
151 	private JMenu desktopMenu;
152 	private JMenu helpMenu;
153 	private JMenu fileMenu;
154 	private static JMenuBar menuBar;
155 	private JDesktopPanelsList desktopPanelsList;
156 
157 	public static boolean checkedGroovyLogMonitor;
158 	
159 	private JPanel overviewPanel;
160 	private JMenu toolsMenu;
161 	private boolean saveOnExit = true;
162 	private InternalDesktopListener internalDesktopListener = new InternalDesktopListener();
163 	private JInspectorPanel mainInspector;
164 	
165 	private static Timer autoSaveTimer;
166 	private static AutoSaveTimerTask autoSaveTimerTask;
167 
168 
169 	// --------------------------- CONSTRUCTORS ---------------------------
170 
171 	private SoapUI()
172 	{
173 	}
174 
175 	private void buildUI()
176 	{
177 		frame.addWindowListener( new MainFrameWindowListener() );
178 		UISupport.setMainFrame( frame );
179 
180 		navigator = new Navigator( workspace );
181 		navigator.addNavigatorListener( new InternalNavigatorListener() );
182 
183 		desktopPanelsList = new JDesktopPanelsList( desktop );
184 
185 		mainInspector = new JInspectorPanel( buildContentPanel(), SwingConstants.LEFT );
186 		mainInspector.addInspector( new JComponentInspector( buildMainPanel(), "Navigator", "The soapUI Navigator", true ) );
187 		mainInspector.setCurrentInspector( "Navigator" );
188 		
189 		frame.setJMenuBar( buildMainMenu() );
190 		frame.getContentPane().add( buildToolbar(), BorderLayout.NORTH );
191 		frame.getContentPane().add( mainInspector, BorderLayout.CENTER );
192 		frame.setDefaultCloseOperation( JFrame.DO_NOTHING_ON_CLOSE );
193 		frame.setSize( 1000, 750 );
194 
195 		mainInspector.setDividerLocation( 250 );
196 		mainInspector.setResizeWeight( 0.1 );
197 		navigator.selectModelItem( workspace );
198 
199 		desktop.addDesktopListener( internalDesktopListener );
200 
201 		ToolTipManager.sharedInstance().setInitialDelay( 200 );
202 		
203 		JTree mainTree = navigator.getMainTree();
204 		DragSource dragSource = DragSource.getDefaultDragSource();
205 		SoapUIDragAndDropHandler navigatorDragAndDropHandler = new SoapUIDragAndDropHandler(
206 					new NavigatorDragAndDropable( mainTree ), DropType.ON + DropType.AFTER );
207 		
208 		dragSource.createDefaultDragGestureRecognizer( mainTree, DnDConstants.ACTION_COPY_OR_MOVE,
209 					navigatorDragAndDropHandler );
210 		
211 		desktop.init();
212 	}
213 
214 	private JComponent buildToolbar()
215 	{
216 		JXToolBar toolbar = new JXToolBar();
217 		toolbar.setRollover( true );
218 		toolbar.putClientProperty( Options.HEADER_STYLE_KEY, HeaderStyle.BOTH );
219 		toolbar.add( new NewWsdlProjectActionDelegate() );
220 		toolbar.add( new ImportWsdlProjectActionDelegate() );
221 		toolbar.add( new SaveAllActionDelegate() );
222 		toolbar.addSeparator();
223 		toolbar.add( new PreferencesActionDelegate() );
224 		toolbar.add( new ExitButtonAction() );
225 		toolbar.addGlue();
226 		
227 		toolbar.add( new ShowOnlineHelpAction( HelpUrls.USERGUIDE_HELP_URL ));
228 		
229 		toolbar.setBorder( BorderFactory.createEtchedBorder() );
230 		
231 		return toolbar;
232 	}
233 
234 	private JMenuBar buildMainMenu()
235 	{
236 		menuBar = new JMenuBar();
237 		menuBar.putClientProperty( Options.HEADER_STYLE_KEY, HeaderStyle.BOTH );
238 
239 		menuBar.add( buildFileMenu() );
240 		menuBar.add( buildToolsMenu() );
241 		menuBar.add( buildDesktopMenu() );
242 		menuBar.add( buildHelpMenu() );
243 
244 		return menuBar;
245 	}
246 
247 	public static Workspace getWorkspace()
248 	{
249 		return workspace;
250 	}
251 
252 	private JMenu buildDesktopMenu()
253 	{
254 		desktopMenu = new JMenu( "Desktop" );
255 		desktopMenu.setMnemonic( KeyEvent.VK_D );
256 		desktopMenu.add( new SwitchDesktopPanelAction( desktopPanelsList ) );
257 		desktopMenu.add( new MaximizeDesktopAction( ( InspectorLog4JMonitor ) logMonitor ) );
258 		desktopMenu.addSeparator();
259 
260 		ActionSupport.addActions( desktop.getActions(), desktopMenu );
261 
262 		return desktopMenu;
263 	}
264 	
265 	private JMenu buildHelpMenu()
266 	{
267 		helpMenu = new JMenu( "Help" );
268 		helpMenu.setMnemonic( KeyEvent.VK_H );
269 
270 		helpMenu.add( new ShowOnlineHelpAction( "User Guide", HelpUrls.USERGUIDE_HELP_URL ) );
271 		helpMenu.add( new ShowOnlineHelpAction( "Getting Started",
272 					HelpUrls.GETTINGSTARTED_HELP_URL ) );
273 		helpMenu.addSeparator();
274 		
275 		helpMenu.add( new ShowSystemPropertiesAction());
276 		
277 		helpMenu.addSeparator();
278 		helpMenu.add( new OpenUrlAction( "soapui.org", "http://www.soapui.org" ) );
279 		helpMenu.add( new AboutAction() );
280 		return helpMenu;
281 	}
282 
283 	@SuppressWarnings("unchecked")
284 	private JMenu buildToolsMenu()
285 	{
286 		toolsMenu = new JMenu( "Tools" );
287 		toolsMenu.setMnemonic( KeyEvent.VK_T );
288 
289 		toolsMenu.add( SwingActionDelegate.createDelegate( WSToolsWsdl2JavaAction.SOAPUI_ACTION_ID ));
290 		toolsMenu.add( SwingActionDelegate.createDelegate( JBossWSConsumeAction.SOAPUI_ACTION_ID ));
291 		toolsMenu.addSeparator();
292 		toolsMenu.add( SwingActionDelegate.createDelegate( WSCompileAction.SOAPUI_ACTION_ID ));
293 		toolsMenu.add( SwingActionDelegate.createDelegate( WSImportAction.SOAPUI_ACTION_ID ));
294 		toolsMenu.addSeparator();
295 		toolsMenu.add( SwingActionDelegate.createDelegate( Axis1XWSDL2JavaAction.SOAPUI_ACTION_ID ));
296 		toolsMenu.add( SwingActionDelegate.createDelegate( Axis2WSDL2CodeAction.SOAPUI_ACTION_ID ));
297 		toolsMenu.add( SwingActionDelegate.createDelegate( CXFAction.SOAPUI_ACTION_ID ));
298 		toolsMenu.add( SwingActionDelegate.createDelegate( XFireAction.SOAPUI_ACTION_ID ));
299 		toolsMenu.add( SwingActionDelegate.createDelegate( OracleWsaGenProxyAction.SOAPUI_ACTION_ID ));
300 		toolsMenu.addSeparator();
301 		toolsMenu.add( SwingActionDelegate.createDelegate( XmlBeans2Action.SOAPUI_ACTION_ID ));
302 		toolsMenu.add( SwingActionDelegate.createDelegate( JaxbXjcAction.SOAPUI_ACTION_ID ));
303 		toolsMenu.addSeparator();
304 		toolsMenu.add( SwingActionDelegate.createDelegate( DotNetWsdlAction.SOAPUI_ACTION_ID ));
305 		toolsMenu.add( SwingActionDelegate.createDelegate( GSoapAction.SOAPUI_ACTION_ID ));
306 		toolsMenu.addSeparator();
307 		toolsMenu.add( SwingActionDelegate.createDelegate( TcpMonAction.SOAPUI_ACTION_ID ));
308 		// toolsMenu.addSeparator();
309 		// toolsMenu.add( new XQueryXPathTesterAction());
310 
311 		return toolsMenu;
312 	}
313 
314 	private JMenu buildFileMenu()
315 	{
316 		fileMenu = new JMenu( "File" );
317 		fileMenu.setMnemonic( KeyEvent.VK_F );
318 
319 		ActionList actions = ActionListBuilder.buildActions( workspace );
320 		actions.removeAction( actions.getActionCount()-1 );
321 
322 		ActionSupport.addActions( actions, fileMenu );
323 
324 		fileMenu.add( SoapUIPreferencesAction.getInstance() );
325 		fileMenu.add( new SavePreferencesAction() );
326 		fileMenu.add( new ImportPreferencesAction() );
327 
328 		fileMenu.addSeparator();
329 		fileMenu.add( buildRecentMenu() );
330 		fileMenu.addSeparator();
331 		fileMenu.add( new ExitAction() );
332 		fileMenu.add( new ExitWithoutSavingAction() );
333 		fileMenu.addSeparator();
334 		fileMenu.add( new ShowOnlineHelpAction( HelpUrls.OVERVIEW_HELP_URL ));
335 		
336 		return fileMenu;
337 	}
338 
339 	private JMenuItem buildRecentMenu()
340 	{
341 		JMenu recentMenu = new JMenu( "Recent" );
342 		
343 		JMenu recentProjectsMenu = new JMenu( "Projects" );
344 		JMenu recentWorkspacesMenu = new JMenu( "Workspaces" );
345 		JMenu recentEditorsMenu = new JMenu( "Editors" );
346 		
347 		recentMenu.add( recentEditorsMenu );
348 		recentMenu.add( recentProjectsMenu );
349 		recentMenu.add( recentWorkspacesMenu );
350 		
351 		RecentItemsListener recentItemsListener = new RecentItemsListener( recentWorkspacesMenu, recentProjectsMenu, recentEditorsMenu );
352 		workspace.addWorkspaceListener( recentItemsListener );
353 		desktop.addDesktopListener( recentItemsListener );
354 		
355 		return recentMenu;
356 	}
357 
358 	public JFrame getFrame()
359 	{
360 		return frame;
361 	}
362 
363 	private JComponent buildMainPanel()
364 	{
365 		JInspectorPanel inspectorPanel = new JInspectorPanel( navigator );
366 		inspectorPanel.addInspector( new JComponentInspector( buildOverviewPanel(), 
367 					"Properties", "Properties for the currently selected item", true ) );
368 		inspectorPanel.setDividerLocation( 500 );
369 		inspectorPanel.setResizeWeight( 0.6 );
370 		inspectorPanel.setCurrentInspector( "Properties" );
371 		
372 		return inspectorPanel;
373 	}
374 
375 	private JComponent buildOverviewPanel()
376 	{
377 		overviewPanel = new JPanel( new BorderLayout() );
378 		overviewPanel.setBorder( BorderFactory.createEmptyBorder( 3, 0, 0, 2 ) );
379 
380 		return overviewPanel;
381 	}
382 
383 	private void setOverviewPanel( Component panel )
384 	{
385 		if( overviewPanel.getComponentCount() == 0 && panel == null )
386 			return;
387 
388 		overviewPanel.removeAll();
389 		if( panel != null )
390 			overviewPanel.add( panel, BorderLayout.CENTER );
391 		overviewPanel.revalidate();
392 		overviewPanel.repaint();
393 	}
394 
395 	private JComponent buildContentPanel()
396 	{
397 		return buildLogPanel( true, "soapUI log" );
398 	}
399 
400 	private JComponent buildLogPanel( boolean hasDefault, String defaultName )
401 	{
402 		InspectorLog4JMonitor inspectorLog4JMonitor = new InspectorLog4JMonitor(desktop.getDesktopComponent());
403 		
404 		JComponent monitor = initLogMonitor( hasDefault, defaultName, inspectorLog4JMonitor );
405 		
406 		if( !SoapUI.getSettings().getBoolean( UISettings.SHOW_LOGS_AT_STARTUP ))
407 			inspectorLog4JMonitor.activate( null );
408 		
409 		MonitorPanel monitorPanel = new MonitorPanel( new RuntimeMemoryMonitorSource() );
410 		monitorPanel.start();
411 		inspectorLog4JMonitor.addInspector( new JComponentInspector( 
412 					monitorPanel, "memory log", "Shows runtime memory consumtion", true ) );
413 		
414 		return monitor;
415 	}
416 
417 	public static JComponent initLogMonitor( boolean hasDefault, String defaultName, Log4JMonitor logMonitor )
418 	{
419 		SoapUI.logMonitor = logMonitor; 
420 		logMonitor.addLogArea( defaultName, "com.eviware.soapui", hasDefault ).setLevel( Level.DEBUG );
421 		logMonitor.addLogArea( "http log", "httpclient.wire", false ).setLevel( Level.DEBUG );
422 		logMonitor.addLogArea( "jetty log", "jetty", false ).setLevel( Level.INFO );
423 		logMonitor.addLogArea( "error log", "soapui.errorlog", false ).setLevel( Level.DEBUG );
424 
425 		for( Object message : logCache )
426 		{
427 			logMonitor.logEvent( message );
428 		}
429 		
430 		return logMonitor.getComponent();
431 	}
432 	
433 	// -------------------------- OTHER METHODS --------------------------
434 
435 	public static synchronized void log( final Object msg )
436 	{
437 		if( logMonitor == null )
438 		{
439 			logCache.add( msg );
440 			return;
441 		}
442 
443 		if( SwingUtilities.isEventDispatchThread() )
444 		{
445 			logMonitor.logEvent( msg );
446 		}
447 		else
448 		{
449 			SwingUtilities.invokeLater( new Runnable()
450 			{
451 				public void run()
452 				{
453 					logMonitor.logEvent( msg );
454 				}
455 			} );
456 		}
457 	}
458 
459 	// -------------------------- INNER CLASSES --------------------------
460 
461 	private final class InternalDesktopListener extends DesktopListenerAdapter
462 	{
463 		public void desktopPanelSelected( DesktopPanel desktopPanel )
464 		{
465 			ModelItem modelItem = desktopPanel.getModelItem();
466 			if( modelItem != null )
467 				navigator.selectModelItem( modelItem );
468 		}
469 	}
470 
471 	private final class MainFrameWindowListener extends WindowAdapter
472 	{
473 		public void windowClosing( WindowEvent e )
474 		{
475 			if( onExit() )
476 				frame.dispose();
477 		}
478 
479 		public void windowClosed( WindowEvent e )
480 		{
481 			System.out.println( "exiting.." );
482 			System.exit( 0 );
483 		}
484 	}
485 
486 	public static void main( String[] args ) throws Exception
487 	{
488 		startSoapUI( args, "soapUI " + SOAPUI_VERSION, "soapui-splash.gif", new StandaloneSoapUICore( true ) );
489 	}
490 	
491 	public static SoapUI startSoapUI( String[] args, String title, String splashImage, SwingSoapUICore core ) throws Exception
492 	{
493 		frame = new JFrame( title );
494 		
495 		SoapUISplash splash = new SoapUISplash( splashImage, frame );
496 		
497 		isStandalone = true;
498 		soapUICore = core;
499 		
500 		SoapUI soapUI = new SoapUI();
501 		Workspace workspace = null;
502 
503 		if( args.length > 0 )
504 		{
505 			workspace = WorkspaceFactory.getInstance().openWorkspace( args );
506 			soapUICore.getSettings().setString( CURRENT_SOAPUI_WORKSPACE, args[0] );
507 		}
508 		else
509 		{
510 			String wsfile = soapUICore.getSettings().getString( CURRENT_SOAPUI_WORKSPACE, System.getProperty( "user.home" ) + File.separatorChar
511 						+ DEFAULT_WORKSPACE_FILE );
512 			workspace = WorkspaceFactory.getInstance().openWorkspace( new String[] { wsfile } );
513 		}
514 		
515 		core.prepareUI();
516 		soapUI.show( workspace );
517 		core.afterStartup( workspace );
518 		Thread.sleep( 500 );
519 		splash.setVisible( false );
520 		
521 		return soapUI;
522 	}
523 	
524 	public static SoapUICore getSoapUICore()
525 	{
526 		return soapUICore;
527 	}
528 
529 	public static void setSoapUICore( SoapUICore soapUICore )
530 	{
531 		SoapUI.soapUICore = soapUICore;
532 	}
533 
534 	public static boolean isStandalone()
535 	{
536 		return isStandalone;
537 	}
538 
539 	public static JMenuBar getMenuBar()
540 	{
541 		return menuBar;
542 	}
543 	
544 	private void show( Workspace workspace )
545 	{
546 		SoapUI.workspace = workspace;
547 
548 		String desktopType = soapUICore.getSettings().getString( UISettings.DESKTOP_TYPE, SoapUI.DEFAULT_DESKTOP);
549 		desktop = DesktopRegistry.getInstance().createDesktop( desktopType, workspace );
550 		
551 		if( desktop == null ) 
552 			desktop = new StandaloneDesktop( workspace );
553 		
554 		if( testMonitor == null )
555 			testMonitor = new TestMonitor();
556 
557 		soapUICore.getSettings().addSettingsListener( new SettingsListener() {
558 
559 			public void settingChanged( String name, String newValue, String oldValue )
560 			{
561 				if( name.equals( UISettings.DESKTOP_TYPE ))
562 				{
563 					changeDesktop( DesktopRegistry.getInstance().createDesktop( newValue, SoapUI.workspace ));
564 				}
565 			}
566 		} );
567 		
568 		buildUI();
569 		
570 		testMonitor.addTestMonitorListener( new LogDisablingTestMonitorListener() );
571 		testMonitor.init( workspace );
572 		frame.setVisible( true );
573 		
574 		initAutoSaveTimer();
575 	}
576 	
577 	private void changeDesktop(SoapUIDesktop newDesktop )
578 	{
579 		desktopPanelsList.setDesktop( newDesktop );
580 		desktop.removeDesktopListener( internalDesktopListener );
581 		
582 		desktop.transferTo( newDesktop );
583 		desktop.release();
584 		
585 		desktop = newDesktop;
586 		
587 		if( logMonitor instanceof InspectorLog4JMonitor )
588 			((InspectorLog4JMonitor)logMonitor).setContentComponent( desktop.getDesktopComponent() );
589 		
590 		desktop.addDesktopListener( internalDesktopListener );
591 		
592 		while( desktopMenu.getItemCount() > DEFAULT_DESKTOP_ACTIONS_COUNT )
593 			desktopMenu.remove( DEFAULT_DESKTOP_ACTIONS_COUNT );
594 		
595 		ActionSupport.addActions( desktop.getActions(), desktopMenu );
596 		
597 		desktop.init();
598 	}
599 	
600 	protected boolean onExit()
601 	{
602 		if( saveOnExit )
603 		{
604 			String question = "Exit SoapUI?";
605 			
606 			if( getTestMonitor().hasRunningTests() )
607 				question += "\n(Projects with running tests will not be saved)";
608 			
609 			if( !UISupport.confirm( question, "Question" ) )
610 				return false;
611 
612 			try
613 			{
614 				PropertyExpansionUtils.saveGlobalProperties();
615 				soapUICore.saveSettings();
616 				workspace.onClose();
617 			}
618 			catch( Exception e1 )
619 			{
620 				SoapUI.logError( e1 );
621 			}
622 		}
623 		else
624 		{
625 			if( !UISupport.confirm( "Exit SoapUI without saving?", "Question" ) )
626 			{
627 				saveOnExit = true;
628 				return false;
629 			}
630 		}
631 		
632 		return true;
633 	}
634 
635 	public static void logError( Throwable e )
636 	{
637 		String msg = e.getMessage();
638 		if( msg == null )
639 			msg = e.toString();
640 		
641 		log.error( "An error occured [" + msg + "], see error log for details" );
642 		errorLog.error(e.toString(), e );
643 		if( !isStandalone() )
644 			e.printStackTrace();
645 	}
646 
647 	public static synchronized Logger ensureGroovyLog()
648 	{
649 		if( !checkedGroovyLogMonitor )
650 		{
651 			Log4JMonitor logMonitor = getLogMonitor();
652 			if( logMonitor != null && !logMonitor.hasLogArea( "groovy.log" ))
653 			{
654 				logMonitor.addLogArea( "groovy log", "groovy.log", false );
655 				checkedGroovyLogMonitor = true;
656 			}
657 		}
658 		
659 		return Logger.getLogger( "groovy.log" );
660 	}
661 
662 	public class InternalNavigatorListener implements NavigatorListener
663 	{
664 		public void nodeSelected( SoapUITreeNode treeNode )
665 		{
666 			if( treeNode == null )
667 			{
668 				setOverviewPanel( null );
669 			}
670 			else
671 			{
672 				ModelItem modelItem = treeNode.getModelItem();
673 				PropertyHolderTable propertyHolderTable = null;
674 				
675 				if( modelItem instanceof TestPropertyHolder )
676 				{
677 					propertyHolderTable = new PropertyHolderTable( ( TestPropertyHolder ) modelItem );
678 				}
679 				
680 				PanelBuilder<ModelItem> panelBuilder = PanelBuilderRegistry.getPanelBuilder( modelItem );
681 				if( panelBuilder != null && panelBuilder.hasOverviewPanel() )
682 				{
683 					Component overviewPanel = panelBuilder.buildOverviewPanel( modelItem );
684 					if( propertyHolderTable != null )
685 					{
686 						JTabbedPane tabs = new JTabbedPane();
687 						if( overviewPanel instanceof JPropertiesTable )
688 						{
689 							JPropertiesTable t = ( JPropertiesTable ) overviewPanel;
690 							tabs.addTab( t.getTitle(), overviewPanel );
691 							t.setTitle( null );
692 						}
693 						else
694 						{
695 							tabs.addTab( "Overview", overviewPanel );
696 						}
697 						tabs.addTab( "Test Properties", propertyHolderTable );
698 						overviewPanel = UISupport.createTabPanel( tabs, false );
699 					}
700 					
701 					setOverviewPanel( overviewPanel );
702 				}
703 				else
704 				{
705 					setOverviewPanel( null );
706 				}
707 			}
708 		}
709 	}
710 
711 	private class ExitAction extends AbstractAction
712 	{
713 		public ExitAction()
714 		{
715 			super( "Exit" );
716 			putValue( Action.SHORT_DESCRIPTION, "Saves all projects and exits SoapUI" );
717 			putValue( Action.ACCELERATOR_KEY, UISupport.getKeyStroke( "menu Q" ) );
718 		}
719 
720 		public void actionPerformed( ActionEvent e )
721 		{
722 			saveOnExit = true;
723 			WindowEvent windowEvent = new WindowEvent( frame, WindowEvent.WINDOW_CLOSING );
724 			frame.dispatchEvent( windowEvent );
725 		}
726 	}
727 	
728 	private class ExitButtonAction extends AbstractAction
729 	{
730 		public ExitButtonAction()
731 		{
732 			putValue( Action.SMALL_ICON, UISupport.createImageIcon( "/system-log-out.png" ));
733 			putValue( Action.SHORT_DESCRIPTION, "Saves all projects and exits SoapUI" );
734 		}
735 
736 		public void actionPerformed( ActionEvent e )
737 		{
738 			saveOnExit = true;
739 			WindowEvent windowEvent = new WindowEvent( frame, WindowEvent.WINDOW_CLOSING );
740 			frame.dispatchEvent( windowEvent );
741 		}
742 	}
743 
744 	private static class ShowSystemPropertiesAction extends AbstractAction
745 	{
746 		public ShowSystemPropertiesAction()
747 		{
748 			super( "System Properties" );
749 			putValue( Action.SHORT_DESCRIPTION, "Shows the current systems properties" );
750 		}
751 
752 		public void actionPerformed( ActionEvent e )
753 		{
754 			StringBuffer buffer = new StringBuffer();
755 			Properties properties = System.getProperties();
756 			
757 			List<String> keys = new ArrayList<String>();
758 			for( Object key : properties.keySet() )
759 				keys.add( key.toString() );
760 			
761 			Collections.sort( keys );
762 			
763 			String lastKey = null;
764 			
765 			for( String key : keys )
766 			{
767 				if( lastKey != null )
768 				{
769 					if( !key.startsWith( lastKey ))
770 						buffer.append(  "\r\n" );
771 				}
772 
773 				int ix = key.indexOf( '.' );
774 				lastKey = ix == -1 ? key : key.substring( 0, ix );
775 				
776 				buffer.append( key ).append( '=' ).append( properties.get( key )).append( "\r\n" );
777 			}
778 			
779 			UISupport.showExtendedInfo( "System Properties", "Current system properties", 
780 						"<html><body><pre><font size=-1>" + buffer.toString() + "</font></pre></body></html>", 
781 						new Dimension( 600, 400 ));
782 		}
783 	}
784 	
785 	private static class AboutAction extends AbstractAction
786 	{
787 		public AboutAction()
788 		{
789 			super( "About soapUI" );
790 			putValue( Action.SHORT_DESCRIPTION, "Shows information on soapUI" );
791 		}
792 
793 		public void actionPerformed( ActionEvent e )
794 		{
795 			URI splashURI = null;
796 			try
797 			{
798 				splashURI = UISupport.findSplash( SoapUI.SOAPUI_SPLASH_GIF ).toURI();
799 			}
800 			catch( URISyntaxException e1 )
801 			{
802 				SoapUI.logError( e1 );
803 			}
804 			
805 			Properties props = new Properties();
806 			try
807 			{
808 				props.load( SoapUI.class.getResourceAsStream( "/buildinfo.txt" ) );
809 			}
810 			catch( Exception e1 )
811 			{
812 				SoapUI.logError( e1 );
813 			}
814 			
815 			
816 			UISupport.showExtendedInfo( "About soapUI", null, 
817 						"<html><body><p align=center><img src=\"" + splashURI + "\"><br>soapUI " +
818 						SOAPUI_VERSION + ", copyright (C) 2004-2007 eviware.com<br>" +
819 						"<a href=\"http://www.soapui.org\">http://www.soapui.org</a> | " +
820 						"<a href=\"http://www.eviware.com\">http://www.eviware.com</a><br>" +
821 									"Build " + props.getProperty( "build.number" ) + ", Build Date " +
822 									props.getProperty( "build.date" ) + "</p></body></html>",
823 									
824 						new Dimension( 470, 350 ));
825 		}
826 	}
827 	
828 	private class ExitWithoutSavingAction extends AbstractAction
829 	{
830 		public ExitWithoutSavingAction()
831 		{
832 			super( "Exit without saving" );
833 			putValue( Action.SHORT_DESCRIPTION, "Saves all projects and exits SoapUI" );
834 			putValue( Action.ACCELERATOR_KEY, UISupport.getKeyStroke( "ctrl alt Q" ) );
835 		}
836 
837 		public void actionPerformed( ActionEvent e )
838 		{
839 			saveOnExit = false;
840 			WindowEvent windowEvent = new WindowEvent( frame, WindowEvent.WINDOW_CLOSING );
841 			frame.dispatchEvent( windowEvent );
842 		}
843 	}
844 
845 	private class SavePreferencesAction extends AbstractAction
846 	{
847 		public SavePreferencesAction()
848 		{
849 			super( "Save Preferences" );
850 			putValue( Action.SHORT_DESCRIPTION, "Saves all global preferences" );
851 		}
852 
853 		public void actionPerformed( ActionEvent e )
854 		{
855 			try
856 			{
857 				soapUICore.saveSettings();
858 			}
859 			catch( Exception e1 )
860 			{
861 				UISupport.showErrorMessage( e1 );
862 			}
863 		}
864 	}
865 	
866 	public static TestMonitor getTestMonitor()
867 	{
868 		if( testMonitor == null )
869 			testMonitor = new TestMonitor();
870 		
871 		return testMonitor;
872 	}
873 
874 	public static void setTestMonitor( TestMonitor monitor )
875 	{
876 		testMonitor = monitor;
877 	}
878 
879 	public static Log4JMonitor getLogMonitor()
880 	{
881 		return logMonitor;
882 	}
883 
884 	public static void setLogMonitor( Log4JMonitor monitor )
885 	{
886 		logMonitor = monitor;
887 	}
888 
889 	// instance is null in Eclipse. /Lars
890 	// eclipse-version(s) should provide SoapUIDesktop implementation
891 	public static SoapUIDesktop getDesktop()
892 	{
893 		return desktop;
894 	}
895 
896 	public static void setDesktop( SoapUIDesktop desktop )
897 	{
898 		SoapUI.desktop = desktop;
899 	}
900 
901 	public static Navigator getNavigator()
902 	{
903 		return navigator;
904 	}
905 	
906 	public static SoapUIActionRegistry getActionRegistry()
907 	{
908 		if( soapUICore == null )
909 			soapUICore = new DefaultSoapUICore();
910 		
911 		return soapUICore.getActionRegistry();
912 	}
913 
914 	public static void setNavigator( Navigator navigator )
915 	{
916 		SoapUI.navigator = navigator;
917 	}
918 
919 	public static void setStandalone( boolean standalone )
920 	{
921 		SoapUI.isStandalone = standalone;
922 	}
923 	
924 	private static class NewWsdlProjectActionDelegate extends AbstractAction
925 	{
926 		public NewWsdlProjectActionDelegate()
927 		{
928 			putValue( Action.SMALL_ICON, UISupport.createImageIcon( "/project.gif" ));
929 			putValue( Action.SHORT_DESCRIPTION, "Creates a new WSDL Project" );
930 		}
931 		
932 		public void actionPerformed( ActionEvent e )
933 		{
934 			SoapUI.getActionRegistry().getAction( NewWsdlProjectAction.SOAPUI_ACTION_ID ).perform( workspace, null );
935 		}
936 	}
937 	
938 	private static class ImportWsdlProjectActionDelegate extends AbstractAction
939 	{
940 		public ImportWsdlProjectActionDelegate()
941 		{
942 			putValue( Action.SMALL_ICON, UISupport.createImageIcon( "/import_project.gif" ));
943 			putValue( Action.SHORT_DESCRIPTION, "Imports an existing WSDL Project into the current workspace" );
944 		}
945 		
946 		public void actionPerformed( ActionEvent e )
947 		{
948 			SoapUI.getActionRegistry().getAction( ImportWsdlProjectAction.SOAPUI_ACTION_ID ).perform( workspace, null );
949 		}
950 	}
951 	
952 	private static class SaveAllActionDelegate extends AbstractAction
953 	{
954 		public SaveAllActionDelegate()
955 		{
956 			putValue( Action.SMALL_ICON, UISupport.createImageIcon( "/disk_multiple.png" ));
957 			putValue( Action.SHORT_DESCRIPTION, "Saves all projects in the current workspace" );
958 		}
959 		
960 		public void actionPerformed( ActionEvent e )
961 		{
962 			SoapUI.getActionRegistry().getAction( SaveAllProjectsAction.SOAPUI_ACTION_ID ).perform( workspace, null );
963 		}
964 	}
965 	
966 	private class PreferencesActionDelegate extends AbstractAction
967 	{
968 		public PreferencesActionDelegate()
969 		{
970 			putValue( Action.SMALL_ICON, UISupport.createImageIcon( "/options.gif" ));
971 			putValue( Action.SHORT_DESCRIPTION, "Sets Global soapUI Options" );
972 		}
973 		
974 		public void actionPerformed( ActionEvent e )
975 		{
976 			SoapUIPreferencesAction.getInstance().actionPerformed( null );
977 		}
978 	}
979 	
980 	public static class ImportPreferencesAction extends AbstractAction
981 	{
982 		public static final String IMPORT_PREFERENCES_ACTION_NAME = "Import Preferences";
983 
984 		public ImportPreferencesAction()
985 		{
986 			super( ImportPreferencesAction.IMPORT_PREFERENCES_ACTION_NAME );
987 			putValue( Action.SHORT_DESCRIPTION, "Imports soapUI Settings from another settings-file" );
988 		}
989 
990 		public void actionPerformed( ActionEvent e )
991 		{
992 			try
993 			{
994 				// prompt for import
995 				File file = UISupport.getFileDialogs().open( null, ImportPreferencesAction.IMPORT_PREFERENCES_ACTION_NAME, ".xml", "soapUI Settings XML (*.xml)", null );
996 				if( file != null )
997 					soapUICore.importSettings( file );
998 			}
999 			catch( Exception e1 )
1000 			{
1001 				UISupport.showErrorMessage( e1 );
1002 			}
1003 		}
1004 	}
1005 	
1006 	public static SoapUIListenerRegistry getListenerRegistry()
1007 	{
1008 		if( soapUICore == null )
1009 			soapUICore = DefaultSoapUICore.createDefault();
1010 		
1011 		return soapUICore.getListenerRegistry();
1012 	}
1013 
1014 	public static Settings getSettings()
1015 	{
1016 		if( soapUICore == null )
1017 			soapUICore = DefaultSoapUICore.createDefault();
1018 		
1019 		return soapUICore.getSettings();
1020 	}
1021 
1022 	public static void importPreferences( File file ) throws Exception
1023 	{
1024 		if( soapUICore != null )
1025 			soapUICore.importSettings( file );
1026 	}
1027 
1028 	public static MockEngine getMockEngine()
1029 	{
1030 		if( soapUICore == null )
1031 			soapUICore = DefaultSoapUICore.createDefault();
1032 		
1033 		return soapUICore.getMockEngine();
1034 	}
1035 
1036 	public static String saveSettings() throws Exception
1037 	{
1038 		return soapUICore == null ? null : soapUICore.saveSettings();
1039 	}
1040 
1041 	public static void initDefaultCore()
1042 	{
1043 		if( soapUICore == null )
1044 			soapUICore = DefaultSoapUICore.createDefault();
1045 	}
1046 	
1047 	public class MaximizeDesktopAction extends AbstractAction
1048 	{
1049 		private JLogList lastLog;
1050 		private int lastMainDividerLocation;
1051 		private final InspectorLog4JMonitor log4JMonitor;
1052 		private int lastLogDividerLocation;
1053 		
1054 		public MaximizeDesktopAction( InspectorLog4JMonitor log4JMonitor )
1055 		{
1056 			super( "Maximize Desktop" );
1057 			this.log4JMonitor = log4JMonitor;
1058 
1059 			putValue( SHORT_DESCRIPTION, "Hides/Shows the Navigator and Log tabs" );
1060 			putValue( ACCELERATOR_KEY, UISupport.getKeyStroke( "menu M" ) );
1061 		}
1062 
1063 		public void actionPerformed( ActionEvent e )
1064 		{
1065 			if( mainInspector.getCurrentInspector() != null || logMonitor.getCurrentLog() != null )
1066 			{
1067 				lastMainDividerLocation = mainInspector.getDividerLocation();
1068 				mainInspector.deactivate();
1069 				
1070 				lastLog = logMonitor.getCurrentLog();
1071 				lastLogDividerLocation = log4JMonitor.getDividerLocation();
1072 				
1073 				log4JMonitor.deactivate();
1074 			}
1075 			else
1076 			{
1077 				mainInspector.setCurrentInspector( "Navigator" );
1078 				mainInspector.setDividerLocation( lastMainDividerLocation == 0 ? 250 : lastMainDividerLocation );
1079 				
1080 				log4JMonitor.setCurrentLog( lastLog );
1081 				log4JMonitor.setDividerLocation( lastLogDividerLocation == 0 ? 500 : lastLogDividerLocation );
1082 			}
1083 		}
1084 	}
1085 	
1086 	public static void initAutoSaveTimer()
1087 	{
1088 		Settings settings = SoapUI.getSettings();
1089 		long interval = settings.getLong( UISettings.AUTO_SAVE_INTERVAL, 0 );
1090 
1091 		if( autoSaveTimerTask != null )
1092 		{
1093 			if( interval == 0 )
1094 				SoapUI.log( "Cancelling AutoSave Timer" );
1095 
1096 			autoSaveTimerTask.cancel();
1097 			autoSaveTimerTask = null;
1098 		}
1099 
1100 		if( interval > 0 )
1101 		{
1102 			autoSaveTimerTask = new AutoSaveTimerTask();
1103 
1104 			SoapUI.log( "Scheduling autosave every " + interval + " minutes" );
1105 			
1106 			if( autoSaveTimer == null )
1107 				autoSaveTimer = new Timer( "AutoSave Timer" );
1108 			
1109 			autoSaveTimer.schedule( autoSaveTimerTask, interval * 1000 * 60, interval * 1000 * 60 );
1110 		}
1111 	}
1112 
1113 	private static class AutoSaveTimerTask extends TimerTask
1114 	{
1115 		@Override
1116 		public void run()
1117 		{
1118 			SoapUI.log( "Autosaving Workspace" );
1119 			((WorkspaceImpl)SoapUI.getWorkspace()).save( false, true );
1120 		}
1121 	}
1122 }