Problems with XML persistence

Hello,

I’m using DockingFrames to implement a dashboard. And so far everything works fine except the xml saving part. When I have some dockables stacked, it’s not loading the layout correctly from the xml file. I’ve uploaded two screenshots to my Picassa account, one with the original layout and another one with the layout loaded from the xml file

The dockables are created using a MultipleCDockableFactory, and the layout is stored and loaded using CControler.writeXML/readXML.

Doing some research, I’ve found that after loading the layout, the stacked dockables are not visible (dockable.isVisible() returns false) and it’s BaseLocation is null. If I make them visible, they show up as individual dockables, so they are no longer stacked.

I don’t know what I’m doing wrong, and I’ve tried everything. Any help will be appreciated.

Thank you!

You are sure the factory works correct? Does not return null, and there are no objects switched? Because I have several applications which load stacked Dockables and they do not show any problems.

You may also try and call „DefaultMultipleCDockable#setRemoveOnClose(false)“ to make sure the framework does not remove dockables that are not used. A you may try to load the layout in the EventDispatcherThread to make sure there are no race conditions.

It could be interesting to see the created xml file, to ensure that the layout was stored correctly.

If that does not help I would need to see more of your application. Maybe a simple example that I can start and run.

Btw., your modifications look very nice. If you are ever interested in publishing them, we could make an extension to the framework :wink:

I’ve tried setting the removeOnClose to false and loading the layout in the EventDispatcherThread, and nothing seems to work. I’m copying the factory, the layout and the dockable, maybe you will see something that’s incorrect or missing.

public class DashboardGadgetDockable extends DefaultMultipleCDockable
{
  private DashboardDragAndDropSinglePanel content;
  
  public DashboardGadgetDockable(DashboardGadgetFactory factory)
  {
    super(factory, "gadgets", null);

    this.setTitleIcon(new ImageIcon());
    
    ((JComponent) this.getContentPane()).setOpaque(true);
    ((JComponent) this.getContentPane()).setBackground(new Color(225, 238, 255));

    this.setCloseable(true);
    this.setMinimizable(false);
    this.setExternalizable(false);
    this.setLayout(new BorderLayout());
    this.setRemoveOnClose(false);
  }

  public DashboardDragAndDropSinglePanel getContent()
  {
    return content;
  }

  public void setContent(DashboardDragAndDropSinglePanel content)
  {
    if (this.content != null)
    {
      this.remove(this.content);
    }
    this.content = content;
    this.content.setGadgetDockable(this);
    this.setTitleText(this.content.getInnerGadget().getGadgetName());
    this.add(this.content, BorderLayout.CENTER);
  }
}
public class DashboardGadgetFactory implements MultipleCDockableFactory<DashboardGadgetDockable, DashboardGadgetLayout>
{
  public DashboardGadgetLayout create()
  {
    return new DashboardGadgetLayout();
  }

  public DashboardGadgetDockable read(DashboardGadgetLayout layout)
  {
    DashboardGadgetDockable dockable = new DashboardGadgetDockable(this);
    dockable.setContent(layout.getContent());
    return dockable;
  }

  public DashboardGadgetLayout write(DashboardGadgetDockable dockable)
  {
    DashboardGadgetLayout layout = create();
    layout.setContent(dockable.getContent());
    return layout;
  }

  public boolean match(DashboardGadgetDockable dockable, DashboardGadgetLayout layout)
  {
    if (dockable.getContent().equals(layout.getContent()))
    {
      return true;
    }
    return false;
  }
}
public class DashboardGadgetLayout implements MultipleCDockableLayout
{
  private DashboardDragAndDropSinglePanel content;

  public void setContent(DashboardDragAndDropSinglePanel content)
  {
    this.content = content;
  }

  public DashboardDragAndDropSinglePanel getContent()
  {
    return content;
  }

  public void readStream(DataInputStream in) throws IOException
  {
  }

  public void readXML(XElement element)
  {
    try 
    {
      DashboardDragAndDropSinglePanel xmlDashboardDragAndDropSinglePanel = 
        new DashboardDragAndDropSinglePanel();
      
      DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); 
      DocumentBuilder db = dbf.newDocumentBuilder();  
      InputSource is = new InputSource(); 
      is.setCharacterStream(new StringReader(element.getString())); 
      Document doc = db.parse(is); 
      NodeList nl = doc.getElementsByTagName("GADGET");
      Node nd = nl.item(0);
      xmlDashboardDragAndDropSinglePanel.fromXML(nd);
      content = xmlDashboardDragAndDropSinglePanel;
    }
    catch (Exception e)
    {
      e.printStackTrace();
    }
  }

  public void writeStream(DataOutputStream out) throws IOException
  {
  }

  public void writeXML(XElement element)
  {
    element.setString(content.toXML());
  }
}

Also, I’m attaching the XML generated for the layout shown in the screencapture in the previous post.

If this isn’t enough, I’ll make a small app so you can try it.

And about the theme, I will ask permission to my boss, but I think there won’t be a problem.

Thank you!

Unfortunately all of this looks good. Assuming the framework works correct (which I admin, is not always the case), then the only possibility I currently see, is that the factories are registered too late. I.e. after the layout is loaded. The framework silently drops data if factories or Dockables are missing.

If that is not the case, then the small app would be very helpful.

One thing you should try first: in the method “DashboardGadgetFactory.match” return always “false”. I doubt it will help, but this method is still young and it is an easy test.

I made a little app that has the basic structure of our dashboard. You just need to execute the DashboardApp file. To add new gadgets press Edit and the gadget toolbar will pop up. Click the button to add new gadgets.

I’ve tested it and it’s still failing to reload the stacked dockables.

Thanks!

PD: I’m using the version 1.1.0p5 of DockingFrames.

And to check if there was something wrong with the version, I’ve just tested it using the old version 1.0.8, and it’s working. So I think there might be a problem in the CControl#addDockable(String p1, M p2).

Strange… I’ll check it out in the evening. Thanks for your efforts anyway.

I have to apologize, this bug really was my fault and I should have noticed myself. I have a repaired version online later this evening.

To explain what happened: There is a filter checking each layout for invalid data. This filter was applied too early and removed some of your dockables because it did not recognize them. The filter is now applied at the correct time.

And I did not notice because my applications, that would have indicated that particular bug, are built such that the filter recognizes the dockables. However, your code is absolutely correct and should work with the next release.

Some optimizations for your code:

  • It is not necessary to call “this.control.save(“layout”);” and “this.control.load(“layout”);” before/after storing/loading the layout.
  • There may be more than one “DashboardGadgetLayout” for the same Dockable. If you use “save” and “load” there certainly is, thus you create many invisible, never used “DashboardDragAndDropSinglePanel”…