001: /*
002: * Copyright 2007 Google Inc.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License"); you may not
005: * use this file except in compliance with the License. You may obtain a copy of
006: * the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
012: * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
013: * License for the specific language governing permissions and limitations under
014: * the License.
015: */
016: package com.google.gwt.dev;
017:
018: import com.google.gwt.core.ext.TreeLogger;
019: import com.google.gwt.core.ext.UnableToCompleteException;
020: import com.google.gwt.core.ext.TreeLogger.Type;
021: import com.google.gwt.core.ext.typeinfo.TypeOracle;
022: import com.google.gwt.dev.cfg.ModuleDef;
023: import com.google.gwt.dev.cfg.ModuleDefLoader;
024: import com.google.gwt.dev.jjs.JJSOptions;
025: import com.google.gwt.dev.shell.BrowserWidget;
026: import com.google.gwt.dev.shell.BrowserWidgetHost;
027: import com.google.gwt.dev.shell.BrowserWidgetHostChecker;
028: import com.google.gwt.dev.shell.LowLevel;
029: import com.google.gwt.dev.shell.ModuleSpaceHost;
030: import com.google.gwt.dev.shell.PlatformSpecific;
031: import com.google.gwt.dev.shell.ShellMainWindow;
032: import com.google.gwt.dev.shell.ShellModuleSpaceHost;
033: import com.google.gwt.dev.shell.tomcat.EmbeddedTomcatServer;
034: import com.google.gwt.dev.util.arg.ArgHandlerGenDir;
035: import com.google.gwt.dev.util.arg.ArgHandlerLogLevel;
036: import com.google.gwt.dev.util.arg.ArgHandlerScriptStyle;
037: import com.google.gwt.dev.util.log.AbstractTreeLogger;
038: import com.google.gwt.util.tools.ArgHandlerDisableAggressiveOptimization;
039: import com.google.gwt.util.tools.ArgHandlerExtra;
040: import com.google.gwt.util.tools.ArgHandlerFlag;
041: import com.google.gwt.util.tools.ArgHandlerOutDir;
042: import com.google.gwt.util.tools.ArgHandlerString;
043: import com.google.gwt.util.tools.ToolBase;
044:
045: import org.eclipse.swt.SWT;
046: import org.eclipse.swt.events.DisposeEvent;
047: import org.eclipse.swt.events.DisposeListener;
048: import org.eclipse.swt.graphics.Cursor;
049: import org.eclipse.swt.graphics.Image;
050: import org.eclipse.swt.graphics.Rectangle;
051: import org.eclipse.swt.internal.Library;
052: import org.eclipse.swt.layout.FillLayout;
053: import org.eclipse.swt.widgets.Display;
054: import org.eclipse.swt.widgets.Shell;
055:
056: import java.io.File;
057: import java.util.ArrayList;
058: import java.util.List;
059: import java.util.Set;
060:
061: /**
062: * The main executable class for the hosted mode shell.
063: */
064: public class GWTShell extends ToolBase {
065:
066: /**
067: * Handles the -blacklist command line argument.
068: */
069: protected class ArgHandlerBlacklist extends ArgHandlerString {
070:
071: @Override
072: public String[] getDefaultArgs() {
073: return new String[] { "-blacklist", "" };
074: }
075:
076: @Override
077: public String getPurpose() {
078: return "Prevents the user browsing URLs that match the specified regexes (comma or space separated)";
079: }
080:
081: @Override
082: public String getTag() {
083: return "-blacklist";
084: }
085:
086: @Override
087: public String[] getTagArgs() {
088: return new String[] { "blacklist-string" };
089: }
090:
091: @Override
092: public boolean setString(String blacklistStr) {
093: return BrowserWidgetHostChecker
094: .blacklistRegexes(blacklistStr);
095: }
096: }
097:
098: /**
099: * handles the -noserver command line flag.
100: */
101: protected class ArgHandlerNoServerFlag extends ArgHandlerFlag {
102: @Override
103: public String getPurpose() {
104: return "Prevents the embedded Tomcat server from running, even if a port is specified";
105: }
106:
107: @Override
108: public String getTag() {
109: return "-noserver";
110: }
111:
112: @Override
113: public boolean setFlag() {
114: runTomcat = false;
115: return true;
116: }
117: }
118:
119: /**
120: * Handles the -port command line flag.
121: */
122: protected class ArgHandlerPort extends ArgHandlerString {
123:
124: @Override
125: public String[] getDefaultArgs() {
126: return new String[] { "-port", "8888" };
127: }
128:
129: @Override
130: public String getPurpose() {
131: return "Runs an embedded Tomcat instance on the specified port (defaults to 8888)";
132: }
133:
134: @Override
135: public String getTag() {
136: return "-port";
137: }
138:
139: @Override
140: public String[] getTagArgs() {
141: return new String[] { "port-number | \"auto\"" };
142: }
143:
144: @Override
145: public boolean setString(String value) {
146: if (value.equals("auto")) {
147: port = 0;
148: } else {
149: try {
150: port = Integer.parseInt(value);
151: } catch (NumberFormatException e) {
152: String msg = "A port must be an integer or \"auto\"";
153: getTopLogger().log(TreeLogger.ERROR, msg, null);
154: return false;
155: }
156: }
157: return true;
158: }
159: }
160:
161: /**
162: * handles the -saveJsni command line flag.
163: */
164: protected class ArgHandlerSaveJsni extends ArgHandlerFlag {
165: @Override
166: public String getPurpose() {
167: return "Save generated JSNI source in the supplied gen directory (if any)";
168: }
169:
170: @Override
171: public String getTag() {
172: return "-saveJsni";
173: }
174:
175: @Override
176: public boolean setFlag() {
177: saveJsni = true;
178: return true;
179: }
180: }
181:
182: /**
183: * Handles the list of startup urls that can be passed on the command line.
184: */
185: protected class ArgHandlerStartupURLs extends ArgHandlerExtra {
186:
187: @Override
188: public boolean addExtraArg(String arg) {
189: addStartupURL(arg);
190: return true;
191: }
192:
193: @Override
194: public String getPurpose() {
195: return "Automatically launches the specified URL";
196: }
197:
198: @Override
199: public String[] getTagArgs() {
200: return new String[] { "url" };
201: }
202: }
203:
204: /**
205: * Handles the -whitelist command line flag.
206: */
207: protected class ArgHandlerWhitelist extends ArgHandlerString {
208:
209: @Override
210: public String[] getDefaultArgs() {
211: return new String[] { "-whitelist", "" };
212: }
213:
214: @Override
215: public String getPurpose() {
216: return "Allows the user to browse URLs that match the specified regexes (comma or space separated)";
217: }
218:
219: @Override
220: public String getTag() {
221: return "-whitelist";
222: }
223:
224: @Override
225: public String[] getTagArgs() {
226: return new String[] { "whitelist-string" };
227: }
228:
229: @Override
230: public boolean setString(String whitelistStr) {
231: return BrowserWidgetHostChecker
232: .whitelistRegexes(whitelistStr);
233: }
234: }
235:
236: private class BrowserWidgetHostImpl implements BrowserWidgetHost {
237: public BrowserWidgetHostImpl() {
238: }
239:
240: public void compile(ModuleDef moduleDef)
241: throws UnableToCompleteException {
242: GWTShell.this .compile(getLogger(), moduleDef);
243: }
244:
245: public void compile(String[] moduleNames)
246: throws UnableToCompleteException {
247: for (int i = 0; i < moduleNames.length; i++) {
248: String moduleName = moduleNames[i];
249: ModuleDef moduleDef = loadModule(moduleName,
250: getLogger());
251: compile(moduleDef);
252: }
253: }
254:
255: public ModuleSpaceHost createModuleSpaceHost(
256: BrowserWidget widget, final String moduleName)
257: throws UnableToCompleteException {
258: TreeLogger logger = getLogger();
259:
260: // Switch to a wait cursor.
261: //
262: Shell widgetShell = widget.getShell();
263: try {
264: Cursor waitCursor = display
265: .getSystemCursor(SWT.CURSOR_WAIT);
266: widgetShell.setCursor(waitCursor);
267:
268: // Try to find an existing loaded version of the module def.
269: //
270: ModuleDef moduleDef = loadModule(moduleName, logger);
271: assert (moduleDef != null);
272:
273: // Create a sandbox for the module.
274: //
275: TypeOracle typeOracle = moduleDef.getTypeOracle(logger);
276: ShellModuleSpaceHost host = doCreateShellModuleSpaceHost(
277: logger, typeOracle, moduleDef, genDir, outDir);
278: return host;
279: } finally {
280: Cursor normalCursor = display
281: .getSystemCursor(SWT.CURSOR_ARROW);
282: widgetShell.setCursor(normalCursor);
283: }
284: }
285:
286: public TreeLogger getLogger() {
287: return getTopLogger();
288: }
289:
290: public String normalizeURL(String whatTheUserTyped) {
291: return GWTShell.this .normalizeURL(whatTheUserTyped);
292: }
293:
294: public BrowserWidget openNewBrowserWindow()
295: throws UnableToCompleteException {
296: return GWTShell.this .openNewBrowserWindow();
297: }
298:
299: /**
300: * Load a module.
301: *
302: * @param moduleName name of the module to load
303: * @param logger TreeLogger to use
304: * @return the loaded module
305: * @throws UnableToCompleteException
306: */
307: private ModuleDef loadModule(final String moduleName,
308: TreeLogger logger) throws UnableToCompleteException {
309: ModuleDef moduleDef = doLoadModule(logger, moduleName);
310: assert (moduleDef != null) : "Required module state is absent";
311: return moduleDef;
312: }
313: }
314:
315: private static Image[] icons;
316:
317: static {
318: // Correct menu on Mac OS X
319: Display.setAppName("GWT");
320: }
321:
322: public static String checkHost(String hostUnderConsideration,
323: Set<String> hosts) {
324: hostUnderConsideration = hostUnderConsideration.toLowerCase();
325: for (String rule : hosts) {
326: // match on lowercased regex
327: if (hostUnderConsideration.matches(".*" + rule + ".*")) {
328: return rule;
329: }
330: }
331: return null;
332: }
333:
334: public static String computeHostRegex(String url) {
335: // the enture URL up to the first slash not prefixed by a slash or colon.
336: String raw = url.split("(?<![:/])/")[0];
337: // escape the dots and put a begin line specifier on the result
338: return "^" + raw.replaceAll("[.]", "[.]");
339: }
340:
341: public static String formatRules(Set<String> invalidHttpHosts) {
342: StringBuffer out = new StringBuffer();
343: for (String rule : invalidHttpHosts) {
344: out.append(rule);
345: out.append(" ");
346: }
347: return out.toString();
348: }
349:
350: /**
351: * Well-known place to get the GWT icons.
352: */
353: public static Image[] getIcons() {
354: // Make sure icon images are loaded.
355: //
356: if (icons == null) {
357: icons = new Image[] { LowLevel.loadImage("icon16.png"),
358: LowLevel.loadImage("icon24.png"),
359: LowLevel.loadImage("icon32.png"),
360: LowLevel.loadImage("icon48.png"),
361: LowLevel.loadImage("icon128.png") };
362: }
363: return icons;
364: }
365:
366: public static void main(String[] args) {
367: /*
368: * NOTE: main always exits with a call to System.exit to terminate any
369: * non-daemon threads that were started in Generators. Typically, this is to
370: * shutdown AWT related threads, since the contract for their termination is
371: * still implementation-dependent.
372: */
373: BootStrapPlatform.go();
374: GWTShell shellMain = new GWTShell();
375: if (shellMain.processArgs(args)) {
376: shellMain.run();
377: }
378: System.exit(0);
379: }
380:
381: /**
382: * Use the default display; constructing a new one would make instantiating
383: * multiple GWTShells fail with a mysterious exception.
384: */
385: protected final Display display = Display.getDefault();
386:
387: protected File outDir;
388:
389: private BrowserWidgetHostImpl browserHost = new BrowserWidgetHostImpl();
390:
391: private final List<Shell> browserShells = new ArrayList<Shell>();
392:
393: private File genDir;
394:
395: private boolean headlessMode = false;
396:
397: private final JJSOptions jjsOptions = new JJSOptions();
398:
399: private TreeLogger.Type logLevel;
400:
401: private ShellMainWindow mainWnd;
402:
403: private int port;
404:
405: private boolean runTomcat = true;
406:
407: private boolean saveJsni = false;
408:
409: private boolean started;
410:
411: private final List<String> startupUrls = new ArrayList<String>();
412:
413: public GWTShell() {
414: this (false, false);
415: }
416:
417: protected GWTShell(boolean forceServer, boolean noURLs) {
418: registerHandler(getArgHandlerPort());
419:
420: if (!forceServer) {
421: registerHandler(new ArgHandlerNoServerFlag());
422: }
423:
424: registerHandler(new ArgHandlerSaveJsni());
425: registerHandler(new ArgHandlerWhitelist());
426: registerHandler(new ArgHandlerBlacklist());
427:
428: registerHandler(new ArgHandlerLogLevel() {
429: @Override
430: public String[] getDefaultArgs() {
431: return new String[] { getTag(), doGetDefaultLogLevel() };
432: }
433:
434: @Override
435: public void setLogLevel(Type level) {
436: logLevel = level;
437: }
438: });
439:
440: registerHandler(new ArgHandlerGenDir() {
441: @Override
442: public void setDir(File dir) {
443: genDir = dir;
444: }
445: });
446:
447: registerHandler(new ArgHandlerSaveJsni());
448:
449: if (!noURLs) {
450: registerHandler(new ArgHandlerStartupURLs());
451: }
452:
453: registerHandler(new ArgHandlerOutDir() {
454: @Override
455: public void setDir(File dir) {
456: outDir = dir;
457: }
458: });
459:
460: registerHandler(new ArgHandlerScriptStyle(jjsOptions));
461:
462: registerHandler(new ArgHandlerDisableAggressiveOptimization() {
463: @Override
464: public boolean setFlag() {
465: jjsOptions.setAggressivelyOptimize(false);
466: return true;
467: }
468: });
469: }
470:
471: public void addStartupURL(String url) {
472: startupUrls.add(url);
473: }
474:
475: public void closeAllBrowserWindows() {
476: while (!browserShells.isEmpty()) {
477: browserShells.get(0).dispose();
478: }
479: }
480:
481: public File getGenDir() {
482: return genDir;
483: }
484:
485: public Type getLogLevel() {
486: return logLevel;
487: }
488:
489: public File getOutDir() {
490: return outDir;
491: }
492:
493: public int getPort() {
494: return port;
495: }
496:
497: public TreeLogger getTopLogger() {
498: return mainWnd.getLogger();
499: }
500:
501: public boolean hasBrowserWindowsOpen() {
502: if (browserShells.isEmpty()) {
503: return false;
504: } else {
505: return true;
506: }
507: }
508:
509: /**
510: * Launch the arguments as Urls in separate windows.
511: */
512: public void launchStartupUrls(final TreeLogger logger) {
513: if (startupUrls != null) {
514: // Launch a browser window for each startup url.
515: //
516: String startupURL = "";
517: try {
518: for (String prenormalized : startupUrls) {
519: startupURL = normalizeURL(prenormalized);
520: logger.log(TreeLogger.TRACE, "Starting URL: "
521: + startupURL, null);
522: BrowserWidget bw = openNewBrowserWindow();
523: bw.go(startupURL);
524: }
525: } catch (UnableToCompleteException e) {
526: logger.log(TreeLogger.ERROR,
527: "Unable to open new window for startup URL: "
528: + startupURL, null);
529: }
530: }
531: }
532:
533: public String normalizeURL(String unknownUrlText) {
534: if (unknownUrlText.indexOf(":") != -1) {
535: // Assume it's a full url.
536: return unknownUrlText;
537: }
538:
539: // Assume it's a trailing url path.
540: //
541: if (unknownUrlText.length() > 0
542: && unknownUrlText.charAt(0) == '/') {
543: unknownUrlText = unknownUrlText.substring(1);
544: }
545:
546: int prt = getPort();
547: if (prt != 80 && prt != 0) {
548: // CHECKSTYLE_OFF: Not really an assembled error message, so no space
549: // after ':'.
550: return "http://localhost:" + prt + "/" + unknownUrlText;
551: // CHECKSTYLE_ON
552: } else {
553: return "http://localhost/" + unknownUrlText;
554: }
555: }
556:
557: /**
558: * Called directly by ShellMainWindow and indirectly via BrowserWidgetHost.
559: */
560: public BrowserWidget openNewBrowserWindow()
561: throws UnableToCompleteException {
562: boolean succeeded = false;
563: Shell s = createTrackedBrowserShell();
564: try {
565: BrowserWidget bw = PlatformSpecific.createBrowserWidget(
566: getTopLogger(), s, browserHost);
567:
568: if (mainWnd != null) {
569: Rectangle r = mainWnd.getShell().getBounds();
570: int n = browserShells.size() + 1;
571: s.setBounds(r.x + n * 50, r.y + n * 50, 800, 600);
572: } else {
573: s.setSize(800, 600);
574: }
575:
576: if (!isHeadless()) {
577: s.open();
578: }
579:
580: bw.onFirstShown();
581: succeeded = true;
582: return bw;
583: } finally {
584: if (!succeeded) {
585: s.dispose();
586: }
587: }
588: }
589:
590: /**
591: * Sets up all the major aspects of running the shell graphically, including
592: * creating the main window and optionally starting the embedded Tomcat
593: * server.
594: */
595: public void run() {
596: try {
597: // Set any platform specific system properties.
598: BootStrapPlatform.setSystemProperties();
599:
600: if (!startUp()) {
601: // Failed to initalize.
602: return;
603: }
604:
605: // Eager AWT initialization for OS X to ensure safe coexistence with SWT.
606: BootStrapPlatform.maybeInitializeAWT();
607:
608: // Tomcat's running now, so launch browsers for startup urls now.
609: launchStartupUrls(getTopLogger());
610:
611: pumpEventLoop();
612:
613: shutDown();
614:
615: } catch (Exception e) {
616: e.printStackTrace();
617: }
618: }
619:
620: public void setCompilerOptions(JJSOptions options) {
621: jjsOptions.copyFrom(options);
622: }
623:
624: public void setGenDir(File genDir) {
625: this .genDir = genDir;
626: }
627:
628: public void setLogLevel(Type level) {
629: this .logLevel = level;
630: }
631:
632: public void setOutDir(File outDir) {
633: this .outDir = outDir;
634: }
635:
636: public void setPort(int port) {
637: this .port = port;
638: }
639:
640: public void setRunTomcat(boolean run) {
641: runTomcat = run;
642: }
643:
644: /**
645: * Compiles a logical module def. The caller can modify the specified module
646: * def programmatically in some cases (this is needed for JUnit support, for
647: * example).
648: */
649: protected void compile(TreeLogger logger, ModuleDef moduleDef)
650: throws UnableToCompleteException {
651: GWTCompiler compiler = new GWTCompiler(moduleDef
652: .getCacheManager());
653: compiler.setCompilerOptions(jjsOptions);
654: compiler.setGenDir(genDir);
655: compiler.setOutDir(outDir);
656: compiler.setModuleName(moduleDef.getName());
657: compiler.setLogLevel(logLevel);
658: compiler.distill(logger, moduleDef);
659: }
660:
661: /**
662: * Creates an instance of ShellModuleSpaceHost (or a derived class) using the
663: * specified constituent parts. This method is made to be overridden for
664: * subclasses that need to change the behavior of ShellModuleSpaceHost.
665: *
666: * @param logger TreeLogger to use
667: * @param typeOracle
668: * @param moduleDef
669: * @param genDir
670: * @return ShellModuleSpaceHost instance
671: */
672: protected ShellModuleSpaceHost doCreateShellModuleSpaceHost(
673: TreeLogger logger, TypeOracle typeOracle,
674: ModuleDef moduleDef, File genDir, File outDir) {
675: return new ShellModuleSpaceHost(logger, typeOracle, moduleDef,
676: genDir, outDir, saveJsni);
677: }
678:
679: /**
680: * Can be override to change the default log level in subclasses. JUnit does
681: * this for example.
682: */
683: protected String doGetDefaultLogLevel() {
684: return "INFO";
685: }
686:
687: /**
688: * Loads a named module. This method can be overridden if the module def needs
689: * to be tweaked (or even created) programmatically -- JUnit integration does
690: * this, for example.
691: */
692: protected ModuleDef doLoadModule(TreeLogger logger,
693: final String moduleName) throws UnableToCompleteException {
694: return ModuleDefLoader.loadFromClassPath(logger, moduleName);
695: }
696:
697: /**
698: * Derived classes can override to prevent automatic update checking.
699: */
700: protected boolean doShouldCheckForUpdates() {
701: return true;
702: }
703:
704: /**
705: * Derived classes can override to set a default port.
706: */
707: protected ArgHandlerPort getArgHandlerPort() {
708: return new ArgHandlerPort();
709: }
710:
711: protected BrowserWidgetHost getBrowserHost() {
712: return browserHost;
713: }
714:
715: protected void initializeLogger() {
716: final AbstractTreeLogger logger = mainWnd.getLogger();
717: logger.setMaxDetail(logLevel);
718: }
719:
720: /**
721: * By default we will open the application window.
722: *
723: * @return true if we are running in headless mode
724: */
725: protected boolean isHeadless() {
726: return headlessMode;
727: }
728:
729: protected boolean notDone() {
730: if (!mainWnd.isDisposed()) {
731: return true;
732: }
733: if (!browserShells.isEmpty()) {
734: return true;
735: }
736: return false;
737: }
738:
739: /**
740: *
741: */
742: protected void pumpEventLoop() {
743: TreeLogger logger = getTopLogger();
744:
745: // Run the event loop. When there are no open shells, quit.
746: //
747: while (notDone()) {
748: try {
749: if (!display.readAndDispatch()) {
750: display.sleep();
751: }
752: } catch (Throwable e) {
753: String msg = e.getMessage();
754: msg = (msg != null ? msg : e.getClass().getName());
755: logger.log(TreeLogger.ERROR, msg, e);
756: }
757: }
758: }
759:
760: protected void setHeadless(boolean headlessMode) {
761: this .headlessMode = headlessMode;
762: }
763:
764: /**
765: *
766: */
767: protected void shutDown() {
768: if (!runTomcat) {
769: return;
770: }
771:
772: // Stop the HTTP server.
773: //
774: EmbeddedTomcatServer.stop();
775: }
776:
777: protected boolean startUp() {
778: if (started) {
779: throw new IllegalStateException(
780: "Startup code has already been run");
781: }
782:
783: started = true;
784:
785: loadRequiredNativeLibs();
786:
787: // Create the main app window.
788: // When it is up and running, it will start the Tomcat server if desired.
789: //
790: openAppWindow();
791:
792: // Initialize the logger.
793: //
794: initializeLogger();
795:
796: if (runTomcat) {
797: // Start the HTTP server.
798: // Use a new thread so that logging that occurs during startup is
799: // displayed immediately.
800: //
801: final int serverPort = getPort();
802:
803: String whyFailed = EmbeddedTomcatServer.start(
804: getTopLogger(), serverPort, outDir);
805: if (whyFailed != null) {
806: System.err.println(whyFailed);
807: return false;
808: }
809:
810: // Record what port Tomcat is actually running on.
811: port = EmbeddedTomcatServer.getPort();
812: }
813:
814: return true;
815: }
816:
817: private Shell createTrackedBrowserShell() {
818: final Shell shell = new Shell(display);
819: FillLayout fillLayout = new FillLayout();
820: fillLayout.marginWidth = 0;
821: fillLayout.marginHeight = 0;
822: shell.setLayout(fillLayout);
823: browserShells.add(shell);
824: shell.addDisposeListener(new DisposeListener() {
825: public void widgetDisposed(DisposeEvent e) {
826: if (e.widget == shell) {
827: browserShells.remove(shell);
828: }
829: }
830: });
831:
832: shell.setImages(getIcons());
833:
834: return shell;
835: }
836:
837: private void loadRequiredNativeLibs() {
838: String libName = null;
839: try {
840: libName = "swt";
841: Library.loadLibrary(libName);
842: } catch (UnsatisfiedLinkError e) {
843: StringBuffer sb = new StringBuffer();
844: sb.append("Unable to load required native library '"
845: + libName + "'");
846: sb.append("\n\tPlease specify the JVM startup argument ");
847: sb.append("\"-Djava.library.path\"");
848: throw new RuntimeException(sb.toString(), e);
849: }
850: }
851:
852: private void openAppWindow() {
853: final Shell shell = new Shell(display);
854:
855: FillLayout fillLayout = new FillLayout();
856: fillLayout.marginWidth = 0;
857: fillLayout.marginHeight = 0;
858: shell.setLayout(fillLayout);
859:
860: shell.setImages(getIcons());
861:
862: boolean checkForUpdates = doShouldCheckForUpdates();
863:
864: mainWnd = new ShellMainWindow(this , shell,
865: runTomcat ? getPort() : 0, checkForUpdates);
866:
867: shell.setSize(700, 600);
868: if (!isHeadless()) {
869: shell.open();
870: }
871: }
872: }
|