/******************************************************************************* * Copyright (c) 2014 Open Door Logistics (www.opendoorlogistics.com) * All rights reserved. This program and the accompanying materials * are made available under the terms of the GNU Lesser Public License v3 * which accompanies this distribution, and is available at http://www.gnu.org/licenses/lgpl.txt ******************************************************************************/ package com.opendoorlogistics.studio; import java.awt.Color; import java.awt.Dimension; import java.awt.event.MouseMotionListener; import java.util.HashMap; import java.util.Map; import javax.swing.JFrame; import javax.swing.ToolTipManager; import javax.swing.UIDefaults; import javax.swing.UIManager; import javax.swing.UIManager.LookAndFeelInfo; import com.opendoorlogistics.api.ODLApi; import com.opendoorlogistics.api.app.ODLApp; import com.opendoorlogistics.api.components.ODLComponent; import com.opendoorlogistics.api.components.ODLStudioLoader; import com.opendoorlogistics.api.standardcomponents.map.MapSelectionList; import com.opendoorlogistics.components.InitialiseComponents; import com.opendoorlogistics.core.InitialiseCore; import com.opendoorlogistics.core.api.impl.ODLApiImpl; import com.opendoorlogistics.core.components.ODLGlobalComponents; import com.opendoorlogistics.core.scripts.execution.ExecutionReportImpl; import com.opendoorlogistics.core.scripts.execution.OptionsSubpath; import com.opendoorlogistics.core.scripts.execution.ScriptExecutionBlackboardImpl; import com.opendoorlogistics.core.scripts.execution.ScriptExecutor; import com.opendoorlogistics.core.scripts.execution.adapters.AdapterBuilder; import com.opendoorlogistics.core.scripts.execution.adapters.FunctionsBuilder; import com.opendoorlogistics.core.scripts.execution.dependencyinjection.AbstractDependencyInjector; import com.opendoorlogistics.core.scripts.execution.dependencyinjection.DependencyInjector; import com.opendoorlogistics.core.scripts.execution.dependencyinjection.DependencyInjectorDecorator; import com.opendoorlogistics.core.scripts.execution.dependencyinjection.ProcessingApiDecorator; import com.opendoorlogistics.studio.appframe.AppFrame; import com.opendoorlogistics.studio.components.geocoder.component.NominatimGeocoderComponent; import com.opendoorlogistics.studio.components.map.GlobalMapPluginManager; import com.opendoorlogistics.studio.components.map.MapApiImpl; import com.opendoorlogistics.studio.components.map.MapConfig; import com.opendoorlogistics.studio.components.map.SuggestedFillValuesManager; import com.opendoorlogistics.studio.components.tables.TableControlComponent; import com.opendoorlogistics.studio.scripts.editor.ScriptEditor; import com.opendoorlogistics.studio.scripts.editor.adapters.AdaptedTableControl; import com.opendoorlogistics.studio.scripts.editor.adapters.AdapterTableDefinitionGrid; import com.opendoorlogistics.studio.scripts.editor.adapters.AdapterTablesTabControl; import com.opendoorlogistics.studio.scripts.editor.adapters.QueryAvailableData; import com.opendoorlogistics.studio.scripts.editor.wizardgenerated.ScriptEditorWizardGenerated; import com.opendoorlogistics.studio.scripts.execution.ScriptUIManager; import com.opendoorlogistics.studio.scripts.execution.ScriptUIManagerImpl; import com.opendoorlogistics.studio.scripts.execution.ScriptsRunner; final public class InitialiseStudio implements ODLStudioLoader{ private static volatile boolean isInit = false; public InitialiseStudio(){ } public static synchronized ODLApi initialise(boolean preloadClasses) { if (!isInit) { // Check the classname is as expected by the API (as its used with reflection) Class<?> cls = InitialiseStudio.class; String className =cls.getName(); if(!className.equals(ODLStudioLoader.LOADER_IMPLEMENTATION_NAME)){ throw new RuntimeException("Loader class has been renamed and no longer equals " + ODLStudioLoader.LOADER_IMPLEMENTATION_NAME + ". This will break code using it by reflection."); } if(!ODLStudioLoader.class.isAssignableFrom(cls)){ throw new RuntimeException("Loader class no longer implements ODLStudioLoader . This will break code using it by reflection."); } initLookAndFeel(); ToolTipManager.sharedInstance().setDismissDelay(Integer.MAX_VALUE); // run app initialisation InitialiseCore.initialise(); InitialiseComponents.initialise(); ODLGlobalComponents.register(new NominatimGeocoderComponent()); MapApiImpl.registerComponent(); ODLGlobalComponents.register(new TableControlComponent()); // hack .. any classes which cause a noticeable pause in the UI when // first loaded are given dummy calls here to put make the loading // occur once-off when the app starts. if (preloadClasses) { preloadClasses(); } isInit = true; } return new ODLApiImpl(); } /** * Preload classes so pauses due to class loading happen at start-up only. */ public static void preloadClasses() { for (Class<?> cls : new Class<?>[] { MapApiImpl.class, MapConfig.class,GlobalMapPluginManager.class, MapSelectionList.class, SuggestedFillValuesManager.class, MouseMotionListener.class, ScriptEditor.class, ScriptEditorWizardGenerated.class, AdaptedTableControl.class, AdapterTableDefinitionGrid.class, AdapterTablesTabControl.class, QueryAvailableData.class, ScriptsRunner.class, ScriptUIManager.class, ScriptUIManagerImpl.class, ScriptExecutor.class, ScriptExecutionBlackboardImpl.class, ExecutionReportImpl.class, AdapterBuilder.class, FunctionsBuilder.class, OptionsSubpath.class, AbstractDependencyInjector.class, DependencyInjector.class, DependencyInjectorDecorator.class, ProcessingApiDecorator.class, com.opendoorlogistics.api.components.ComponentExecutionApi.ClosedStateListener.class, com.opendoorlogistics.api.distances.ODLCostMatrix.class, com.opendoorlogistics.codefromweb.BlockingLifoQueue.class, com.opendoorlogistics.codefromweb.DesktopScrollPane.class, com.opendoorlogistics.codefromweb.jxmapviewer2.DesktopPaneMapViewer.DesktopPanePanMouseInputListener.class, com.opendoorlogistics.codefromweb.jxmapviewer2.DesktopPaneMapViewer.DesktopPaneZoomMouseWheelListenerCursor.class, com.opendoorlogistics.codefromweb.jxmapviewer2.fork.beans.AbstractBean.class, com.opendoorlogistics.codefromweb.jxmapviewer2.fork.swingx.mapviewer.AbstractTileFactory.class, com.opendoorlogistics.codefromweb.jxmapviewer2.fork.swingx.mapviewer.empty.EmptyTileFactory.class, com.opendoorlogistics.codefromweb.jxmapviewer2.fork.swingx.mapviewer.GeoPosition.class, com.opendoorlogistics.codefromweb.jxmapviewer2.fork.swingx.mapviewer.Tile.class, com.opendoorlogistics.codefromweb.jxmapviewer2.fork.swingx.mapviewer.Tile.Priority.class, com.opendoorlogistics.codefromweb.jxmapviewer2.fork.swingx.mapviewer.TileCache.class, com.opendoorlogistics.codefromweb.jxmapviewer2.fork.swingx.mapviewer.TileFactory.class, com.opendoorlogistics.codefromweb.jxmapviewer2.fork.swingx.mapviewer.TileFactoryInfo.class, com.opendoorlogistics.codefromweb.jxmapviewer2.fork.swingx.mapviewer.TileListener.class, com.opendoorlogistics.codefromweb.jxmapviewer2.fork.swingx.mapviewer.util.GeoUtil.class, com.opendoorlogistics.codefromweb.jxmapviewer2.fork.swingx.OSMTileFactoryInfo.class, com.opendoorlogistics.codefromweb.jxmapviewer2.fork.swingx.painter.AbstractPainter.class, com.opendoorlogistics.codefromweb.jxmapviewer2.fork.swingx.painter.AbstractPainter.Interpolation.class, com.opendoorlogistics.codefromweb.jxmapviewer2.fork.swingx.painter.CompoundPainter.class, com.opendoorlogistics.codefromweb.jxmapviewer2.fork.swingx.painter.Painter.class, com.opendoorlogistics.core.api.impl.GeometryImpl.class, com.opendoorlogistics.core.cache.ApplicationCache.class, com.opendoorlogistics.core.cache.RecentlyUsedCache.class, com.opendoorlogistics.core.distances.DistancesSingleton.class, com.opendoorlogistics.core.distances.functions.FmAbstractDrivingCost.class, com.opendoorlogistics.core.distances.functions.FmAbstractTravelCost.class, com.opendoorlogistics.core.distances.functions.FmDistance.class, com.opendoorlogistics.core.distances.functions.FmDistance.Km.class, com.opendoorlogistics.core.distances.functions.FmDistance.Metres.class, com.opendoorlogistics.core.distances.functions.FmDistance.Miles.class, com.opendoorlogistics.core.distances.functions.FmDrivingDistance.class, com.opendoorlogistics.core.distances.functions.FmDrivingDistance.Km.class, com.opendoorlogistics.core.distances.functions.FmDrivingDistance.Metres.class, com.opendoorlogistics.core.distances.functions.FmDrivingDistance.Miles.class, com.opendoorlogistics.core.distances.functions.FmDrivingRouteGeom.class, com.opendoorlogistics.core.distances.functions.FmDrivingRouteGeomFromLine.class, com.opendoorlogistics.core.distances.functions.FmDrivingTime.class, com.opendoorlogistics.core.formulae.definitions.FunctionDefinition.class, com.opendoorlogistics.core.formulae.definitions.FunctionDefinition.ArgumentType.class, com.opendoorlogistics.core.formulae.definitions.FunctionDefinition.FunctionArgument.class, com.opendoorlogistics.core.formulae.definitions.FunctionDefinition.FunctionType.class, com.opendoorlogistics.core.formulae.definitions.FunctionDefinitionLibrary.class, com.opendoorlogistics.core.formulae.FormulaParser.class, com.opendoorlogistics.core.formulae.FunctionFactory.class, com.opendoorlogistics.core.formulae.FunctionImpl.class, com.opendoorlogistics.core.formulae.Functions.class, com.opendoorlogistics.core.formulae.Functions.Fm1DoubleParam.class, com.opendoorlogistics.core.formulae.Functions.Fm1GeometryParam.class, com.opendoorlogistics.core.formulae.Functions.FmAbs.class, com.opendoorlogistics.core.formulae.Functions.FmAcos.class, com.opendoorlogistics.core.formulae.Functions.FmAnd.class, com.opendoorlogistics.core.formulae.Functions.FmAsin.class, com.opendoorlogistics.core.formulae.Functions.FmAtan.class, com.opendoorlogistics.core.formulae.Functions.FmCeil.class, com.opendoorlogistics.core.formulae.Functions.FmColour.class, com.opendoorlogistics.core.formulae.Functions.FmColourImage.class, com.opendoorlogistics.core.formulae.Functions.FmColourMultiply.class, com.opendoorlogistics.core.formulae.Functions.FmRelativeComparisonBase.class, com.opendoorlogistics.core.formulae.Functions.FmConcatenate.class, com.opendoorlogistics.core.formulae.Functions.FmConst.class, com.opendoorlogistics.core.formulae.Functions.FmContains.class, com.opendoorlogistics.core.formulae.Functions.FmCos.class, com.opendoorlogistics.core.formulae.Functions.FmDecimalFormat.class, com.opendoorlogistics.core.formulae.Functions.FmDivide.class, com.opendoorlogistics.core.formulae.Functions.FmEquals.class, com.opendoorlogistics.core.formulae.Functions.FmFadeImage.class, com.opendoorlogistics.core.formulae.Functions.FmFloor.class, com.opendoorlogistics.core.formulae.Functions.FmGreaterThan.class, com.opendoorlogistics.core.formulae.Functions.FmGreaterThanEqualTo.class, com.opendoorlogistics.core.formulae.Functions.FmIfThenElse.class, com.opendoorlogistics.core.formulae.Functions.FmImageFilter.class, com.opendoorlogistics.core.formulae.Functions.FmIndexOf.class, com.opendoorlogistics.core.formulae.Functions.FmLeft.class, com.opendoorlogistics.core.formulae.Functions.FmLen.class, com.opendoorlogistics.core.formulae.Functions.FmLerp.class, com.opendoorlogistics.core.formulae.Functions.FmLessThan.class, com.opendoorlogistics.core.formulae.Functions.FmLessThanEqualTo.class, com.opendoorlogistics.core.formulae.Functions.FmLn.class, com.opendoorlogistics.core.formulae.Functions.FmLog10.class, com.opendoorlogistics.core.formulae.Functions.FmLower.class, com.opendoorlogistics.core.formulae.Functions.FmMax.class, com.opendoorlogistics.core.formulae.Functions.FmMin.class, com.opendoorlogistics.core.formulae.Functions.FmMod.class, com.opendoorlogistics.core.formulae.Functions.FmMultiply.class, com.opendoorlogistics.core.formulae.Functions.FmOr.class, com.opendoorlogistics.core.formulae.Functions.FmPostcodeUk.class, com.opendoorlogistics.core.formulae.Functions.FmRand.class, com.opendoorlogistics.core.formulae.Functions.FmRandColour.class, com.opendoorlogistics.core.formulae.Functions.FmRandomSymbol.class, com.opendoorlogistics.core.formulae.Functions.FmReplace.class, com.opendoorlogistics.core.formulae.Functions.FmRound.class, com.opendoorlogistics.core.formulae.Functions.FmRound2Second.class, com.opendoorlogistics.core.formulae.Functions.FmSin.class, com.opendoorlogistics.core.formulae.Functions.FmSingleString.class, com.opendoorlogistics.core.formulae.Functions.FmSqrt.class, com.opendoorlogistics.core.formulae.Functions.FmSubtract.class, com.opendoorlogistics.core.formulae.Functions.FmSum.class, com.opendoorlogistics.core.formulae.Functions.FmSwitch.class, com.opendoorlogistics.core.formulae.Functions.FmTan.class, com.opendoorlogistics.core.formulae.Functions.FmTemperatureColours.class, com.opendoorlogistics.core.formulae.Functions.FmTime.class, com.opendoorlogistics.core.formulae.Functions.FmUpper.class, com.opendoorlogistics.core.formulae.FunctionUtils.class, com.opendoorlogistics.core.formulae.StringTokeniser.class, com.opendoorlogistics.core.formulae.StringTokeniser.StringToken.class, com.opendoorlogistics.core.geometry.functions.FmCentroid.class, com.opendoorlogistics.core.geometry.functions.FmGeom.GeomType.class, com.opendoorlogistics.core.geometry.functions.FmGeomBorder.class, com.opendoorlogistics.core.geometry.functions.FmLatitude.class, com.opendoorlogistics.core.geometry.functions.FmLongitude.class, com.opendoorlogistics.core.geometry.functions.FmShapefileLookup.class, com.opendoorlogistics.core.geometry.GreateCircle.class, com.opendoorlogistics.core.geometry.Spatial.class, com.opendoorlogistics.core.gis.map.background.BackgroundTileFactorySingleton.class, com.opendoorlogistics.core.gis.map.CachedGeomImageRenderer.class, com.opendoorlogistics.core.gis.map.data.LatLongBoundingBox.class, com.opendoorlogistics.core.gis.map.DatastoreRenderer.class, com.opendoorlogistics.core.gis.map.JXMapUtils.class, com.opendoorlogistics.core.gis.map.ObjectRenderer.class, com.opendoorlogistics.core.gis.map.RecentImageCache.class, com.opendoorlogistics.core.gis.map.RecentImageCache.ZipType.class, com.opendoorlogistics.core.gis.map.RenderProperties.class, com.opendoorlogistics.core.gis.map.Symbols.class, com.opendoorlogistics.core.gis.map.Symbols.SymbolType.class, com.opendoorlogistics.core.gis.map.tiled.ChangedObjectsCalculator.class, com.opendoorlogistics.core.gis.map.tiled.NOPLManager.class, com.opendoorlogistics.core.gis.map.tiled.TileCacheRenderer.class, com.opendoorlogistics.core.gis.map.transforms.LatLongToScreenImpl.class, com.opendoorlogistics.core.gis.postcodes.UKPostcodes.UKPostcodeLevel.class, com.opendoorlogistics.core.scripts.execution.adapters.FunctionsBuilder.ProcessedLookupReferences.class, com.opendoorlogistics.core.scripts.execution.adapters.FunctionsBuilder.ToProcessLookupReferences.class, com.opendoorlogistics.core.scripts.formulae.FmAbstractLookup.class, com.opendoorlogistics.core.scripts.formulae.image.FmImage.Mode.class, com.opendoorlogistics.core.scripts.formulae.FmIsSelectedInMap.class, com.opendoorlogistics.core.scripts.formulae.FmLocalElement.class, com.opendoorlogistics.core.scripts.formulae.FmLookup.class, com.opendoorlogistics.core.scripts.formulae.FmLookup.LookupType.class, com.opendoorlogistics.core.scripts.formulae.FmLookupGeomUnion.class, com.opendoorlogistics.core.scripts.formulae.FmLookupNearest.class, com.opendoorlogistics.core.scripts.formulae.FmLookupWeightedCentroid.class, com.opendoorlogistics.core.scripts.formulae.FmRow.class, com.opendoorlogistics.core.scripts.formulae.FmRowId.class, com.opendoorlogistics.core.scripts.formulae.TableParameters.class, com.opendoorlogistics.core.scripts.TableReference.class, com.opendoorlogistics.core.tables.concurrency.WriteRecorderDecorator.class, com.opendoorlogistics.core.tables.decorators.datastores.RowFilterDecorator.class, com.opendoorlogistics.core.tables.decorators.datastores.UnionDecorator.class, com.opendoorlogistics.core.tables.decorators.listeners.ListenerRedirector.class, com.opendoorlogistics.core.utils.NullComparer.class, com.opendoorlogistics.core.utils.SimpleSoftReferenceMap.class, com.opendoorlogistics.core.utils.strings.StandardisedCache.class, com.opendoorlogistics.core.utils.strings.StringKeyValue.class, com.opendoorlogistics.core.utils.strings.Strings.ToString.class, com.opendoorlogistics.core.utils.ui.SwingUtils.class, com.opendoorlogistics.studio.GlobalMapSelectedRowsManager.GlobalSelectionChangedCB.class, com.opendoorlogistics.studio.internalframes.ProgressFrame.class, com.opendoorlogistics.studio.scripts.execution.ScriptsRunner.class, com.opendoorlogistics.studio.components.map.plugins.snapshot.CreateImageConfig.class, com.opendoorlogistics.studio.components.map.plugins.snapshot.ExportImageConfig.class, }) { cls.toString(); } } private static void initLookAndFeel() { // get the defaults to keep HashMap<Object, Object> defaultsToKeep = new HashMap<>(); for (Map.Entry<Object, Object> entry : UIManager.getDefaults().entrySet()) { // keep progress bar string defaults (as nimbus looks rubbish) boolean isStringKey = entry.getKey().getClass() == String.class ; String key = isStringKey ? ((String) entry.getKey()):""; boolean keep =key.startsWith("ProgressBar"); // keep tabbed pane defaults as nimbus to prevent re-ordering http://stackoverflow.com/questions/7481991/jtabbedpane-avoid-automatic-re-ordering-tabs-if-stacked-nimbus if(!keep){ // see list of properties here http://www.java2s.com/Tutorial/Java/0240__Swing/CustomizingaJTabbedPaneLookandFeel.htm keep = key.startsWith("TabbedPane"); } if (keep) { defaultsToKeep.put(entry.getKey(), entry.getValue()); } } // set look and feel try { boolean set = false; for (LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) { if ("Nimbus".equals(info.getName())) { UIManager.setLookAndFeel(info.getClassName()); // UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); UIDefaults defaults = UIManager.getLookAndFeelDefaults(); defaults.put("Table.gridColor", new Color(214, 217, 223)); defaults.put("Table.disabled", false); defaults.put("Table.showGrid", true); defaults.put("Table.intercellSpacing", new Dimension(1, 1)); defaults.put("nimbusOrange", defaults.get("nimbusBase")); set = true; break; } } if (!set) { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); } } catch (Throwable e) { throw new RuntimeException(e); } // copy back progress bar defaults for (Map.Entry<Object, Object> entry : defaultsToKeep.entrySet()) { UIManager.getDefaults().put(entry.getKey(), entry.getValue()); } JFrame.setDefaultLookAndFeelDecorated(true); } @Override public ODLApp startStudio(ODLComponent... components) { // ensure classes are preloaded, even if we've done a no-preload init before initialise(true); preloadClasses(); return new AppFrame(); } @Override public ODLApi createApi() { // do a lazy (no preloading) initialisation initialise(false); return new ODLApiImpl(); } }