Disallowing insertion of the specific block

Hello!

I recently stumbled upon a strange problem. I have several nodes in my application, which can be inserted as many times as a user likes. But I also have one special node, which should be inserted only once. So I have a single object that reffers to that node, if it exists on the document. If it doesn't exist, the object is null. So what I would like to do is to restrain the insertion of any kind (cut / copy / paste, drag / drop...) of that particular object if it already is part of the document without affecting the insertion of the other nodes.
I have tried different approaches: using the onLayerChanged to delete the block once inserted, but it didn't work out quite right, and I'm sure there's a better sollution, then I tried using goView's dragEnter and dragDrop events, but it also failed. I have also overriden the document's add method, but the drag / drop action doesn't use it. I have been thinking about goDocument's allowInsert, but it's somehow global - affects all the nodes.
Please, could you give me any ideas how to go with this? Thanks.

Yes, you have tried to fix things up after various events, but you’re right – that’s not going to work in general.

The GoDiagram architecture was specifically designed to support this uncommon scenario. You need to have your GoDocument perform all copying operations using a custom GoCopyDictionary that is initialized to include that special singleton node.

[code] [Serializable]
public class SpecialDocument : GoDocument {
public SpecialDocument() {}

public override GoCopyDictionary CreateCopyDictionary() {
  GoCopyDictionary env = new SpecialCopyDictionary();
  env.DestinationDocument = this;
  if (this.SpecialNode != null) {
    env[this.SpecialNode] = this.SpecialNode;
    GoGroup g = this.SpecialNode as GoGroup;
    if (g != null) {
      // this might need to be recursive, if your nodes might have more than one level of grouping
      foreach (GoObject obj in g) {
        env[obj] = obj;
      }
    }
  }
  return env;
}

}

goView1.Document = new SpecialDocument();[/code]

However, if you want dynamic recognition of which nodes are the “same” as your SpecialNode, you can’t initialize the GoCopyDictionary to map the SpecialNode to itself, since you don’t know statically what the source node might be. This is typically the case when dragging nodes in from another control, including other GoViews, including GoPalette.

In such a case you need to define a custom GoCopyDictionary and override GoCopyDictionary.Copy to return your SpecialNode when the argument GoObject is a “matching” node. The same goes for parts of your SpecialNode, such as GoPorts if you want copied links to magically connect to your singleton SpecialNode.

[code] [Serializable]
public class SpecialCopyDictionary : GoCopyDictionary {
public SpecialCopyDictionary() {}

public override GoObject Copy(GoObject obj) {
  if (obj == null) return null;
  SpecialDocument doc = this.DestinationDocument as SpecialDocument;
  if (doc != null && doc.SpecialNode != null && ...obj-matches-SpecialNode...) return doc.SpecialNode;
  return base.Copy(obj);
}

}

[Serializable]
public class SpecialDocument : GoDocument {
public SpecialDocument() {}

public override GoCopyDictionary CreateCopyDictionary() {
  GoCopyDictionary env = new SpecialCopyDictionary();
  env.DestinationDocument = this;
  return env;
}

public GoNode SpecialNode { ... }

}

goView1.Document = new SpecialDocument();[/code]