/** * OrbisGIS is a java GIS application dedicated to research in GIScience. * OrbisGIS is developed by the GIS group of the DECIDE team of the * Lab-STICC CNRS laboratory, see <http://www.lab-sticc.fr/>. * * The GIS group of the DECIDE team is located at : * * Laboratoire Lab-STICC – CNRS UMR 6285 * Equipe DECIDE * UNIVERSITÉ DE BRETAGNE-SUD * Institut Universitaire de Technologie de Vannes * 8, Rue Montaigne - BP 561 56017 Vannes Cedex * * OrbisGIS is distributed under GPL 3 license. * * Copyright (C) 2007-2014 CNRS (IRSTV FR CNRS 2488) * Copyright (C) 2015-2017 CNRS (Lab-STICC UMR CNRS 6285) * * This file is part of OrbisGIS. * * OrbisGIS is free software: you can redistribute it and/or modify it under the * terms of the GNU General Public License as published by the Free Software * Foundation, either version 3 of the License, or (at your option) any later * version. * * OrbisGIS is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along with * OrbisGIS. If not, see <http://www.gnu.org/licenses/>. * * For more information, please consult: <http://www.orbisgis.org/> * or contact directly: * info_at_ orbisgis.org */ package org.orbisgis.docking.impl; import bibliothek.extension.gui.dock.preference.PreferenceTreeDialog; import bibliothek.extension.gui.dock.preference.PreferenceTreeModel; import bibliothek.gui.dock.ToolbarDockStation; import bibliothek.gui.dock.common.CControl; import bibliothek.gui.dock.common.CLocation; import bibliothek.gui.dock.common.MultipleCDockableFactory; import bibliothek.gui.dock.common.SingleCDockable; import bibliothek.gui.dock.common.action.CAction; import bibliothek.gui.dock.common.event.CControlListener; import bibliothek.gui.dock.common.intern.CDockable; import bibliothek.gui.dock.common.intern.DefaultCDockable; import bibliothek.gui.dock.common.menu.CLookAndFeelMenuPiece; import bibliothek.gui.dock.common.menu.SingleCDockableListMenuPiece; import bibliothek.gui.dock.facile.menu.RootMenuPiece; import bibliothek.gui.dock.themes.ThemeManager; import bibliothek.gui.dock.toolbar.CToolbarContentArea; import bibliothek.gui.dock.util.*; import bibliothek.util.PathCombiner; import bibliothek.util.xml.XElement; import bibliothek.util.xml.XIO; import java.awt.Graphics; import java.awt.event.ActionListener; import java.beans.EventHandler; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.LinkedHashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; import javax.swing.Action; import javax.swing.JFrame; import javax.swing.JMenu; import javax.swing.SwingUtilities; import javax.swing.SwingWorker; import javax.swing.UIManager; import org.orbisgis.commons.events.BeanPropertyChangeSupport; import org.orbisgis.docking.icons.DockingIcon; import org.orbisgis.docking.impl.internals.ApplicationRessourceDecorator; import org.orbisgis.docking.impl.internals.CustomMultipleCDockable; import org.orbisgis.docking.impl.internals.CustomPanelHolder; import org.orbisgis.docking.impl.internals.CustomSingleCDockable; import org.orbisgis.docking.impl.internals.DockingArea; import org.orbisgis.docking.impl.internals.DockingPanelLayoutDecorator; import org.orbisgis.docking.impl.internals.InternalCommonFactory; import org.orbisgis.docking.impl.internals.OrbisGISView; import org.orbisgis.docking.impl.internals.actions.CActionHolder; import org.orbisgis.docking.impl.internals.actions.ToolBarActions; import org.orbisgis.docking.impl.internals.actions.ToolBarItem; import org.orbisgis.docking.impl.preferences.OrbisGISPreferenceTreeModel; import org.orbisgis.docking.impl.preferences.editors.UserInformationEditor; import org.orbisgis.mainframe.api.MainWindow; import org.orbisgis.mainframe.api.ToolBarAction; import org.orbisgis.sif.components.actions.ActionFactoryService; import org.orbisgis.sif.components.actions.ActionTools; import org.orbisgis.sif.components.actions.ActionsHolder; import org.orbisgis.sif.components.actions.MenuTrackerAction; import org.orbisgis.sif.docking.DockingManager; import org.orbisgis.sif.docking.DockingPanel; import org.orbisgis.sif.docking.DockingPanelFactory; import org.orbisgis.sif.docking.DockingPanelLayout; import org.orbisgis.sif.common.MenuCommonFunctions; import org.osgi.service.component.annotations.Component; import org.osgi.service.component.annotations.Reference; import org.osgi.service.component.annotations.ReferenceCardinality; import org.osgi.service.component.annotations.ReferencePolicy; import org.osgi.service.component.annotations.ReferencePolicyOption; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.xnap.commons.i18n.I18n; import org.xnap.commons.i18n.I18nFactory; /** * Initialize and manage CControl. * * This manager can save and load emplacement of views in XML. */ @Component(service = DockingManager.class) public final class DockingManagerImpl extends BeanPropertyChangeSupport implements DockingManager, ActionsHolder { private JFrame owner; private SingleCDockableListMenuPiece dockableMenuTracker; private static final I18n I18N = I18nFactory.getI18n(DockingManagerImpl.class); private static final Logger LOGGER = LoggerFactory.getLogger("gui." + DockingManagerImpl.class); private File dockingState = null; private static final boolean DOCKING_STATE_XML = true; private CControl commonControl; /*!< link to the docking-frames */ //Docking Area (DockingFrames feature named WorkingArea) private Map<String, DockingArea> dockingAreas = new HashMap<>(); /** * the available preferences for docking frames */ private PreferenceTreeModel preferences; private CToolbarContentArea area; // In order to separate toolbars keep unique count private int createdToolbars = 0; // Action provided to this DockingManager private List<Action> addedToolBarActions = new LinkedList<Action>(); private Map<ActionFactoryService, MenuTrackerAction> actionFromFactory = new HashMap<>(); private MainWindow mainWindow; @Reference public void setMainWindow(MainWindow mainWindow) { this.mainWindow = mainWindow; this.owner = mainWindow.getMainFrame(); // Method bibliothek.gui.dock.util.DockUtilities.checkLayoutLocked(DockUtilities.java:723) // Throw a RuntimeException: java.lang.Error: Trampoline must not be defined by the bootstrap classloader DockUtilities.disableCheckLayoutLocked(); commonControl = new CControl(owner); commonControl.addControlListener(new DockingListener()); dockableMenuTracker = new SingleCDockableListMenuPiece(commonControl); //Retrieve the Docking Frames Preferences preferences = new OrbisGISPreferenceTreeModel(commonControl, PathCombiner.APPEND); commonControl.setPreferenceModel(preferences); //DEFAULT property of a view // commonControl.getController().getProperties().set( PropertyKey.DOCK_STATION_TITLE, I18N.tr("Docked // Window") ); commonControl.getController().getProperties().set(PropertyKey.DOCK_STATION_ICON, DockingIcon.getIcon ("orbisgis")); commonControl.getController().getThemeManager().setBackgroundPaint(ThemeManager.BACKGROUND_PAINT + ".station" + ".toolbar.container", new ToolBarBackGround()); commonControl.putProperty(ToolbarDockStation.SIDE_GAP, 2); commonControl.putProperty(ToolbarDockStation.GAP, 2); //StackDockStation will contain all instances of ReservedDockStation area = new CToolbarContentArea(commonControl, "base"); commonControl.addStationContainer(area); owner.add(area); } public void unsetMainWindow(MainWindow mainWindow) { this.owner = null; } /** * @return the managed frame */ @Override public JFrame getOwner() { return owner; } @Override public void removeDockingPanel(String dockId) { if (SwingUtilities.isEventDispatchThread()) { commonControl.removeSingleDockable(dockId); } else { RemovePanel removePanel = new RemovePanel(commonControl, dockId); try { SwingUtilities.invokeAndWait(removePanel); } catch (Exception ex) { LOGGER.error(ex.getLocalizedMessage(), ex); } } } /** * Used by declarative services * @param dockingPanel Panel instance to remove */ public void removeDockingPanel(DockingPanel dockingPanel) { if (SwingUtilities.isEventDispatchThread()) { commonControl.removeSingleDockable(dockingPanel.getDockingParameters().getName()); } else { RemovePanel removePanel = new RemovePanel(commonControl, dockingPanel.getDockingParameters().getName()); try { SwingUtilities.invokeAndWait(removePanel); } catch (Exception ex) { LOGGER.error(ex.getLocalizedMessage(), ex); } } } /** * @return The look and feel menu */ @Override public JMenu getLookAndFeelMenu() { RootMenuPiece laf = new RootMenuPiece(I18N.tr("&Look And Feel"), false, new CLookAndFeelMenuPiece (commonControl)); JMenu menu = laf.getMenu(); MenuCommonFunctions.setMnemonic(menu); return menu; } /** * @return The menu that shows items declared in the docking */ @Override public JMenu getCloseableDockableMenu() { RootMenuPiece windows = new RootMenuPiece(I18N.tr("&Windows"), false, dockableMenuTracker); JMenu menu = windows.getMenu(); MenuCommonFunctions.setMnemonic(menu); return menu; } /** * Serialise the entire panels workspace */ private void readXML() { try { // Read the entire XML file in memory BufferedInputStream in = new BufferedInputStream(new FileInputStream(dockingState)); XElement element = XIO.readUTF(in); in.close(); // Use the docking frame serialisation commonControl.readXML(element); // Use OrbisGIS serialisation for (CustomPanelHolder panel : getPanelDecorator()) { // Only SingleCDockable is not managed for custom layout information if (panel instanceof CustomSingleCDockable) { CustomSingleCDockable scdockable = (CustomSingleCDockable) panel; DockingPanelLayout layout = scdockable.getDockingPanel().getDockingParameters().getLayout(); if (layout != null) { commonControl.getResources().put(scdockable.getUniqueId(), new ApplicationRessourceDecorator (new DockingPanelLayoutDecorator(layout))); } } } } catch (IOException | IllegalArgumentException ex) { LOGGER.error(I18N.tr("Unable to load the docking layout."), ex); } // When reading a layout file, all components that are not in the layout file are hidden by DockingFrames // Some components cannot be hidden or shown by the user, the following lines // restore the visibility these components. // Check that non closable frame are shown for (CustomPanelHolder holder : getPanelDecorator()) { DockingPanel panel = holder.getDockingPanel(); if (!panel.getDockingParameters().isCloseable() && holder instanceof SingleCDockable) { ((SingleCDockable) holder).setVisible(true); } } // Check that all non empty toolbars are visible // Empty hidden toolbars are kept in order to restore/save the layout. boolean doReset = false; for (ToolBarItem item : getToolBarItems()) { if (!item.isVisible() && item.getAction() != null) { doReset = true; // Reset layout // Unlink action and removed ToolBar item item.resetItem(); commonControl.removeSingleDockable(item.getUniqueId()); } } if (doReset) { resetToolBarsCActions(addedToolBarActions); } else { // All toolbars have been set to visible in order to set layout // The visible state can be reset here // Set the visibility of all ToolBarItems refreshToolBarsState(); } } private void writeXML() throws IOException { // Not visible toolbars cannot retrieve their state on next OrbisGIS loading for (ToolBarItem item : getToolBarItems()) { item.setVisible(true); item.setTrackActionVisibleState(false); } // Make an empty XML tree XElement root = new XElement("root"); // Use the docking frame serialisation commonControl.writeXML(root); // Save the tree in the file BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(dockingState)); XIO.writeUTF(root, out); out.close(); // Recover original state refreshToolBarsState(); } /** * Apply the ToolBar action visible state to their ToolBarItems */ private void refreshToolBarsState() { for (ToolBarItem item : getToolBarItems()) { Action itemAction = item.getAction(); if (itemAction != null) { item.setVisible(ActionTools.isVisible(itemAction)); } else { item.setVisible(false); } item.setTrackActionVisibleState(true); } } /** * Load the docking layout */ private void loadLayout() { if (dockingState != null) { if (dockingState.exists()) { if (DOCKING_STATE_XML) { readXML(); } } } } /** * Save the docking layout */ @Override public void saveLayout() { if (dockingState != null) { try { if (DOCKING_STATE_XML) { writeXML(); } } catch (IOException ex) { LOGGER.error(I18N.tr("Unable to save the docking layout."), ex); } } } /** * Show the preference dialog, on the owner, * with at least the preference model of DockingFrames */ @Override public void showPreferenceDialog() { PreferenceTreeDialog dialog = new PreferenceTreeDialog(preferences, true); //Add custom editors dialog.setEditorFactory(UserInformationEditor.TYPE_USER_INFO, UserInformationEditor.FACTORY); //Show dialog dialog.openDialog(owner, true); } @Override public void registerPanelFactory(String factoryName, DockingPanelFactory factory) { InternalCommonFactory dockingFramesFactory = new InternalCommonFactory(factory, commonControl); commonControl.addMultipleDockableFactory(factoryName, dockingFramesFactory); } @Override public void unregisterPanelFactory(String factoryName) { commonControl.removeMultipleDockableFactory(factoryName); } /** * Free docking resources and save the layout */ @Override public void dispose() { commonControl.destroy(); } /** * For UnitTest purpose only * * @param panel * @return DefaultCDockable instance, null if not exists */ public CDockable getDockable(DockingPanel panel) { int count = commonControl.getCDockableCount(); for (int i = 0; i < count; i++) { CDockable libComponent = commonControl.getCDockable(i); if (libComponent instanceof CustomPanelHolder) { DockingPanel cPanel = ((CustomPanelHolder) libComponent).getDockingPanel(); if (cPanel.equals(panel)) { return libComponent; } } } return null; } /** * Get the intermediate panels * * @return */ private List<CustomPanelHolder> getPanelDecorator() { List<CustomPanelHolder> activePanel = new LinkedList<CustomPanelHolder>(); int count = commonControl.getCDockableCount(); for (int i = 0; i < count; i++) { CDockable dockable = commonControl.getCDockable(i); if (dockable instanceof CustomPanelHolder) { activePanel.add(((CustomPanelHolder) dockable)); } } return activePanel; } private List<ToolBarItem> getToolBarItems() { List<ToolBarItem> toolBarItemList = new LinkedList<ToolBarItem>(); int count = commonControl.getCDockableCount(); for (int i = 0; i < count; i++) { CDockable dockable = commonControl.getCDockable(i); if (dockable instanceof ToolBarItem) { toolBarItemList.add((ToolBarItem) dockable); } } return toolBarItemList; } /** * Get the current opened panels * * @return */ @Override public List<DockingPanel> getPanels() { List<DockingPanel> activePanel = new ArrayList<DockingPanel>(); for (CustomPanelHolder holder : getPanelDecorator()) { activePanel.add(holder.getDockingPanel()); } return activePanel; } /** * DockingManagerImpl will load and save the panels layout * in the specified file. Load the layout if the file exists. * * @param dockingStateFilePath Destination of the default persistence file */ @Override public void setDockingLayoutPersistanceFilePath(String dockingStateFilePath) { this.dockingState = new File(dockingStateFilePath); loadLayout(); } /** * Create a new dockable corresponding to this layout * * @param factoryId The factory id registerPanelFactory:factoryName * @param panelLayout */ @Override public void show(String factoryId, DockingPanelLayout panelLayout) { MultipleCDockableFactory<?, ?> factory = commonControl.getMultipleDockableFactory(factoryId); if (factory != null && factory instanceof InternalCommonFactory) { InternalCommonFactory iFactory = (InternalCommonFactory) factory; CustomMultipleCDockable dockItem = iFactory.read(new DockingPanelLayoutDecorator(panelLayout)); if (dockItem != null) { OrbisGISView.applyDefaultLocation(dockItem, dockItem.getDockingPanel(), commonControl); commonControl.addDockable(dockItem); } } } @Override @Reference(cardinality = ReferenceCardinality.MULTIPLE, policy = ReferencePolicy.DYNAMIC, policyOption = ReferencePolicyOption.GREEDY) public void addDockingPanel(DockingPanel frame) { if (SwingUtilities.isEventDispatchThread()) { show(frame); } else { AddPanel addPanel = new AddPanel(this, frame); try { SwingUtilities.invokeAndWait(addPanel); } catch (Exception ex) { LOGGER.error(ex.getLocalizedMessage(), ex); return; } addPanel.getPanelId(); } } /** * Shows a view at the given location as child * of <code>root</code>. * * @param frame the <code>DockingPanel</code> for which a view should be opened * @return Dockable unique ID */ private String show(DockingPanel frame) { //Create the DockingFrame item if (frame.getDockingParameters().getName().isEmpty()) { //If the dev doesn't define a name on the panel //We set the name as the name of the class frame.getDockingParameters().setName(frame.getClass().getCanonicalName()); } SingleCDockable dockItem = OrbisGISView.createSingle(frame, commonControl); //Place the item in a dockstation String restrictedAreaName = frame.getDockingParameters().getDockingArea(); if (!restrictedAreaName.isEmpty()) { //This item is restricted to an area DockingArea dockArea = dockingAreas.get(restrictedAreaName); if (dockArea == null) { dockArea = new DockingArea(commonControl.createWorkingArea(restrictedAreaName)); dockArea.getWorkingArea().setVisible(true); dockingAreas.put(restrictedAreaName, dockArea); } dockItem.setWorkingArea(dockArea.getWorkingArea()); dockArea.getWorkingArea().add(dockItem); } commonControl.addDockable(dockItem); return dockItem.getUniqueId(); } @Override public void addAction(Action action) { addToolbarItem(action); } @Override public void addActions(List<Action> newActions) { List<Action> before = new ArrayList<Action>(addedToolBarActions); addedToolBarActions.addAll(newActions); resetToolBarsCActions(addedToolBarActions); propertyChangeSupport.firePropertyChange(PROP_ACTIONS, before, addedToolBarActions); } @Override public boolean removeAction(Action action) { removeActions(Arrays.asList(action)); return addedToolBarActions.contains(action); } @Override public void removeActions(List<Action> actionList) { List<Action> before = new ArrayList<Action>(addedToolBarActions); addedToolBarActions.removeAll(actionList); resetToolBarsCActions(addedToolBarActions); propertyChangeSupport.firePropertyChange(PROP_ACTIONS, before, addedToolBarActions); } @Override public String addToolbarItem(Action action) { addActions(Arrays.asList(action)); return ActionTools.getMenuId(action); } private ToolBarItem addToolbarItem(CAction cAction, Action action, CLocation defaultLocation) { String id = ActionTools.getMenuId(action); if (id == null || commonControl.getSingleDockable(id) != null) { // Create a unique ID int inc = 1; id = "action-" + inc; while (commonControl.getSingleDockable(id) != null) { inc++; } String oldId = ""; if (ActionTools.getMenuId(action) != null) { oldId = ActionTools.getMenuId(action); } LOGGER.warn(I18N.tr("ToolBar item {0} is not unique, it has been renamed to {1}", oldId, id)); action.putValue(ActionTools.MENU_ID, id); } ToolBarItem toolbar = new ToolBarItem(id, cAction); commonControl.addDockable(toolbar); try { setLocation(toolbar, defaultLocation); } catch (RuntimeException ex) { LOGGER.error(ex.getLocalizedMessage(), ex); } return toolbar; } /** * Find the most appropriate Location by reading group and insert instruction in Action properties. * * @param toolbar New ToolBarItem, must be already registered in the CControl */ private void setLocation(ToolBarItem toolbar, CLocation defaultLocation) { Action action = toolbar.getAction(); // Default location is north boolean locationSet = false; // Read actions properties String actionId = ActionTools.getMenuId(action); String insertAfter = ActionTools.getInsertAfterMenuId(action); String insertBefore = ActionTools.getInsertBeforeMenuId(action); String logicalGroup = ActionTools.getLogicalGroup(action); // Read other toolbars properties // Find specified placement by item key for (ToolBarItem toolBarItem : getToolBarItems()) { // If this is not the same object instance if (toolBarItem != toolbar) { Action activeAction = toolBarItem.getAction(); String activeId = ActionTools.getMenuId(activeAction); String activeInsertAfter = ActionTools.getInsertAfterMenuId(activeAction); String activeInsertBefore = ActionTools.getInsertBeforeMenuId(activeAction); if ((!insertAfter.isEmpty() && insertAfter.equals(activeId)) || (!activeInsertBefore.isEmpty() && activeInsertBefore.equals(actionId))) { setNextPosition(toolBarItem, toolbar); locationSet = true; break; } else if ((!insertBefore.isEmpty() && insertBefore.equals(activeId)) || (!activeInsertAfter.isEmpty () && activeInsertAfter.equals(actionId))) { setNextPosition(toolBarItem, toolbar); setNextPosition(toolbar, toolBarItem); locationSet = true; break; } } } // If not found use the logical group if (!locationSet && !logicalGroup.isEmpty()) { ToolBarItem lastGroupItem = null; for (ToolBarItem toolBarItem : getToolBarItems()) { // If this is not the same object instance if (toolBarItem != toolbar) { Action activeAction = toolBarItem.getAction(); String activeLogicalGroup = ActionTools.getLogicalGroup(activeAction); if ((!logicalGroup.isEmpty() && activeLogicalGroup.equals(logicalGroup))) { lastGroupItem = toolBarItem; } } } if (lastGroupItem != null) { setNextPosition(lastGroupItem, toolbar); locationSet = true; } } if (!locationSet) { toolbar.setLocation(defaultLocation); toolbar.setVisible(true); } } @Override public boolean removeToolbarItem(Action action) { String id = ActionTools.getMenuId(action); return id != null && commonControl.removeSingleDockable(id); } private void setNextPosition(ToolBarItem item, ToolBarItem itemNext) { if (!item.isVisible()) { item.setVisible(true); } // itemNext.setLocationsAside(item); CLocation location = commonControl.getLocationManager().getLocation(item.intern()); if (location != null) { itemNext.setLocation(location.aside()); itemNext.setVisible(true); } } /** * Recreate all CAction and put them in already shown ToolBarItems. * Remove toolbars that hold action not provided and add toolbars. * * @param actions Actions to show in toolbars */ private void resetToolBarsCActions(List<Action> actions) { // Key: Logical Value: Last set location Map<String, CLocation> lastToolBarLocation = new HashMap<String, CLocation>(); // Create root CAction, the size of rootActions might be smaller than actions ToolBarActions toolBarCActions = new ToolBarActions(); toolBarCActions.setActions(actions); List<CAction> rootActions = toolBarCActions.getCustomActions(); // Create Map of newly generated CActions in order to optimize updates checks. // Key: Action Menu ID Map<String, CAction> actionMap = new HashMap<String, CAction>(rootActions.size()); Set<String> generatedId = new LinkedHashSet<String>(); for (CAction action : rootActions) { if (action instanceof CActionHolder) { String key = ActionTools.getMenuId(((CActionHolder) action).getAction()); actionMap.put(key, action); generatedId.add(key); } else { // Ignore Menu Separator } } // Update and remove toolbars for (ToolBarItem item : getToolBarItems()) { String shownRootMenuId = item.getUniqueId(); CAction newCAction = actionMap.get(shownRootMenuId); if (newCAction == null) { // This ToolBarItem has to be reset item.resetItem(); } else { // The ToolBarItem's CAction must be replaced by the new one generatedId.remove(shownRootMenuId); item.setItem(newCAction); if (!item.isVisible()) { item.setVisible(true); } } } for (String newActionId : generatedId) { CAction newCAction = actionMap.get(newActionId); Action action = ((CActionHolder) newCAction).getAction(); // Default Location depends on String logicalGroup = ActionTools.getLogicalGroup(action); CLocation defaultLocation = getDefaultLocation(lastToolBarLocation, logicalGroup); lastToolBarLocation.put(logicalGroup, defaultLocation); addToolbarItem(newCAction, action, defaultLocation); } refreshToolBarsState(); } @SuppressWarnings("deprecation") private CLocation getDefaultLocation(Map<String, CLocation> lastToolBarLocation, String logicalGroupId) { CLocation defaultLocation = lastToolBarLocation.get(logicalGroupId); if (defaultLocation == null) { defaultLocation = area.getNorthToolbar().getStationLocation().group(createdToolbars++).toolbar(0, 0).item (0); } else { // Aside is deprecated but It has to be used if the ToolBarItem is new. defaultLocation = defaultLocation.aside(); } return defaultLocation; } @Reference(cardinality = ReferenceCardinality.MULTIPLE, policy = ReferencePolicy.DYNAMIC, policyOption = ReferencePolicyOption.GREEDY) public void addToolBarFactory(ToolBarAction factory) { addActionFactory(factory, mainWindow); } public void removeToolBarFactory(ToolBarAction factory) { removeActionFactory(factory); } @Override public <TargetComponent> void addActionFactory(ActionFactoryService<TargetComponent> factory, TargetComponent targetComponent) throws IllegalArgumentException { SwingUtilities.invokeLater(new AddToolBarFactory<TargetComponent>(this, factory, targetComponent)); } private <TargetComponent> void doAddActionFactory(ActionFactoryService<TargetComponent> factory, TargetComponent targetComponent) { if (!actionFromFactory.containsKey(factory)) { MenuTrackerAction<TargetComponent> menuTrackerAction = new MenuTrackerAction<>(factory, factory .createActions(targetComponent), targetComponent); addActions(menuTrackerAction.getActions()); actionFromFactory.put(factory, menuTrackerAction); } else { LOGGER.error("ActionFactoryService instance is already pushed"); } } @Override public <TargetComponent> void removeActionFactory(ActionFactoryService<TargetComponent> actionFactoryService) { MenuTrackerAction<TargetComponent> trackerAction = actionFromFactory.get(actionFactoryService); if (trackerAction != null) { removeActions(trackerAction.getActions()); actionFactoryService.disposeActions(trackerAction.getTargetComponent(), trackerAction.getActions()); actionFromFactory.remove(actionFactoryService); } } /** * When a dockable is added, this listener * read the OrbisGIS DockingPanelParameters of the panel * and apply to the DockingFrames panel instance */ private class DockingListener implements CControlListener { @Override public void added(CControl control, CDockable dockable) { if (dockable instanceof CustomPanelHolder && dockable instanceof DefaultCDockable) { CustomPanelHolder dockItem = (CustomPanelHolder) dockable; OrbisGISView.setListeners(dockItem.getDockingPanel(), (DefaultCDockable) dockable); } else if (!(dockable instanceof ToolBarItem)) { LOGGER.error("Unknown dockable, not an OrbisGIS approved component."); } } @Override public void removed(CControl control, CDockable dockable) { } @Override public void opened(CControl control, CDockable dockable) { } @Override public void closed(CControl control, CDockable dockable) { } } private static class ToolBarBackGround implements BackgroundPaint { @Override public void install(BackgroundComponent backgroundComponent) { } @Override public void uninstall(BackgroundComponent backgroundComponent) { //ignore } @Override public void paint(BackgroundComponent backgroundComponent, PaintableComponent paintable, Graphics g) { paintable.paintBackground(null); g.setColor(UIManager.getColor("Panel.background")); int w = paintable.getComponent().getWidth(); int h = paintable.getComponent().getHeight(); g.fillRect(0, 0, w, h); } } private static class AddPanel implements Runnable { private final DockingManagerImpl dockingManager; private final DockingPanel dockingPanel; private String panelId; private AddPanel(DockingManagerImpl dockingManager, DockingPanel dockingPanel) { this.dockingManager = dockingManager; this.dockingPanel = dockingPanel; } @Override public void run() { panelId = dockingManager.show(dockingPanel); } public String getPanelId() { return panelId; } } private static class RemovePanel implements Runnable { private final CControl control; private final String panelId; private RemovePanel(CControl control, String panelId) { this.control = control; this.panelId = panelId; } @Override public void run() { control.removeSingleDockable(panelId); } } private static class AddToolBarFactory<TargetComponent> extends SwingWorker { private DockingManagerImpl dockingManager; private ActionFactoryService<TargetComponent> factory; private TargetComponent targetComponent; public AddToolBarFactory(DockingManagerImpl dockingManager, ActionFactoryService<TargetComponent> factory, TargetComponent targetComponent) { this.dockingManager = dockingManager; this.factory = factory; this.targetComponent = targetComponent; } @Override protected Object doInBackground() throws Exception { dockingManager.doAddActionFactory(factory, targetComponent); return null; } @Override public String toString() { return I18N.tr("Register toolbar.."); } } }