Determining if a dockable is docked

Hi,

What is the best way to determine whether a Dockable has been docked before?

I have a scenario where some external code gives an id for a component and a location where it should be docked. This code is also responsible for providing a JComponent for that id.

My code first get’s a Dockable from that id using DockableFactory. If the dockable has already been created before then an instance of the dockable will be returned. If the dockable has not been created, then DockableFactory first gets the JComponent for that id from the external code, then creates a Dockable using that JComponent, adds it to the Frontend and returns the Dockable.

When I get this Dockable I would like to know if it has already been docked before. If it has been docked, then I will simply invoke frontend.show(dockable), otherwise I will drop it at an appropriate location.

Here is the code that get’s invoked to show a component.

private void showComponent(String componentId)
        {
            Dockable dockable = 
                _dockableFactoryImpl.layout(new DockLayout<String>(FACTORY_ID, 
                                                                                    componentId));
            if(_frontend.isHidden(dockable))
            {
                _frontend.show(dockable);
            }
            else
            {
                LbComponentLayout layout = 
                    _componentFactory.getComponentLayout(componentId);
                LbComponentLayout.RegionEnum region = layout.getRegion();
                float ratio = layout.getRatio();
                _rootDockingStation.drop(dockable, 
                                                 getSplitDockPathProperty(region, 
                                                 ratio));
            }
        }

Here is my DockFactory and an implementation of DefaultDockable.

static class LbDockableView  extends DefaultDockable
    {    
        public LbDockableView(String id, JComponent dockedComponent)
        {
            super(dockedComponent, id);
            setFactoryID(FACTORY_ID);
        }
        
        public String getId()
        {
            return getTitleText();
        }
    }
private class DockableFactoryImpl 
                            implements DockFactory<LbDockableView, DockLayout<String>>
    {
        private Map<String, LbDockableView> _dockedViews;
        
        DockableFactoryImpl()
        {
            _dockedViews = new HashMap<String, LbDockableView>();
        }
        
        @Override
        public String getID()
        {
            return FACTORY_ID;
        }

        @Override
        public DockLayout<String> getLayout(LbDockableView element,
                Map<Dockable, Integer> children)
        {
            DockLayout<String> layout = new DockLayout<String>(FACTORY_ID, 
                                                                                element.getId()); 
            return layout;
        }

        @Override
        public LbDockableView layout(DockLayout<String> layout)
        {
            return layout(layout, null);
        }

        @Override
        public LbDockableView layout(DockLayout<String> layout,
                Map<Integer, Dockable> children)
        {
            String id = layout.getData();
            LbDockableView dockableView = _dockedViews.get(id);
            if(dockableView == null)
            {
                JComponent component = _componentFactory.getComponent(id);
                LbComponentLayout situation = _componentFactory.getComponentLayout(id);
                dockableView = createView(component, id, situation.isCloseEnabled());
                _dockedViews.put(id, dockableView);
            }
            return dockableView;
        }

        @Override
        public DockLayout<String> read(DataInputStream in) throws IOException
        {
            // TODO: Review the correctness of this
            return new DockLayout<String>(FACTORY_ID, in.readUTF());
        }

        @Override
        public DockLayout<String> read(XElement element)
        {
            return 
                new DockLayout<String>(FACTORY_ID, 
                                              element.getElement(FACTORY_ID).getString());
        }

        @Override
        public void setLayout(LbDockableView element, DockLayout<String> layout)
        {
            //TODO: Not sure how to implement this method. I do not think we need it
        }

        @Override
        public void setLayout(LbDockableView element, DockLayout<String> layout,
                Map<Integer, Dockable> children)
        {
            //TODO: Not sure how to implement this method. I do not think we need it
        }

        @Override
        public void write(DockLayout<String> layout, DataOutputStream out)
                throws IOException
        {
            out.writeUTF(layout.getData());
        }

        @Override
        public void write(DockLayout<String> layout, XElement element)
        {
            element.addElement(FACTORY_ID).setString(layout.getData());
        }
        
        private LbDockableView createView(JComponent component, String id,
                boolean closeEnabled)
        {
            LbDockableView view = new LbDockableView(id, component);
            _frontend.add(view, view.getId());
            if (!closeEnabled)
            {
                _frontend.setHideable(view, false);
            }
            return view;
        }
        
        private void setTitlebarVisibility(boolean visibility)
        {
            //TODO: Implement
            List<Dockable> dockables = _frontend.listDockables();
            for(Dockable dockable : dockables)
            {
                DockTitle dockTitles[] = dockable.listBoundTitles();
                for(DockTitle dockTitle : dockTitles)
                {
                    dockTitle.getComponent().setVisible(visibility);
                }
            }
        }
        
        private int visibleDockablesCount()
        {
            // TODO: Does this give us the list of Dockables that are displayed as 
            //opposed to Dockables that are registered?
            Set<Dockable> shownDockables = _frontend.listShownDockables();
            return shownDockables.size();
        }
    }

I would ask the DockFrontend for all Dockables that are currently registered - „DockFrontend.listDockables()“, and then search in the result (=a java.util.List) of your Dockable.

If you did not register the Dockable (using „DockFrontend.add“) at the DockFrontend, than it is not in the list :stuck_out_tongue: But in that case, calling DockFrontend.show does not make sense anyway, the Dockable would be dropped at a random location…

My problem is that the Dockable is registered with Frontend by my implementation of DockFactory in the layout(…) method.

So when my code which is responsible for showing the Dockable get’s an instance it’s instance from the factory, it (Dockable) will have just been registered (even if it has never been docked before). This will cause dockFrontend.listDockables() to contain that dockable.

The code will thus incorrectly think that the Dockable was docked before and will invoke dockFrontend.show(…) instead of dockFrontend.drop(…).

Right now I am using a quick fix by setting a boolean flag in my dockable instance to indicate if it has been docked. Can I invoke some DockingFrames API which can tell me if a dockable has been docked (considering the situation where it may have been registered with DockFrontend but not actually docked. A false should be returned in this case)


Regards
Parag Shah

Sometimes I forget my own API… please try the method “DockFrontend.hasLocation( Dockable dockable )”. That checks whether the Frontend knows the location of dockable.