FindNearestGridPoint

Hello,
I am trying the 2.4 release and FindNearestGridPoint has disappeared. Where did it go? What do I use now? The readme recommends reading release notes on previous versions. I have no idea where to find this information. How can I find release notes on previous versions?

You don’t need previous release notes for this issue. Due to the new GoGrid class, that particular GoView method didn’t make sense any more. You might just want to change your code to call the same method on GoView.Grid.
Here’s the relevant section from the 2.4 release notes:

GoGrid<?:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

· added IGoDragSnapper interface, to allow objects to control dragging behavior

· added GoGrid, implementing IGoDragSnapper

· added GoView.BackgroundGrid property and GoView.CreateGrid method

· reimplemented GoView grid properties to delegate to the GoView.Grid object, that is either GoView.BackgroundGrid or GoView.Sheet.Grid

· removed GoView.DrawGrid... methods (now on GoGrid)

· added GoView.SnapPoint method, that looks for IGoDragSnapper objects

· removed GoView.FindNearestGridPoint method (now on GoGrid) If you are just calling FindNearestGridPoint instead of overriding it, you can probably just change: goView1.FindNearestGridPoint(...) to: goView1.Grid.FindNearestGridPoint(...)

Thanks,
I will give this a try.

Hello Walter,
I am finally looking at this again. I have updated the code to use the GoGrid class. The new FindNearestGridPoint takes an extra argument which I passed in null. Changing a number of these calls is the only changes I needed to make (other than changing one override from protected to public). I now am unable to draw links between my GoPorts. It appears that when I click drag my GoPorts, it is now being interpeted as a “move” instead of a “Create Link” operation. I did not write this code, so I may be missing something basic.
Do you have any guess to why this functionality would have changed due to an upgrade from 2.1.2 to 2.4.1?
Thanks,
Craig

Does your application ever modify any of the GoView.MouseDownTools or .MouseMoveTools lists?
In 2.3 we changed the standard instance of the GoToolLinkingNew tool by moving it from the MouseDownTools list to the MouseMoveTools list.
If you have code to replace the GoToolDragging tool with your own dragging tool, and you did so by finding and removing the standard one and by inserting your new one at the beginning of the MouseMoveTools list, perhaps you would get that behavior.
It’s normal and more convenient to just call GoView.ReplaceMouseTool when you want to replace a tool, since that GoView method will replace a tool while keeping the relative position in the list the same.

Hi Walter,
Thanks for the quick reply (and on a weekend!). You have me pointed in the right direction. There is some code dealing with the GoToolDraggingTool. Some code is doing a tool replace as you recommend, but there was also an override for the tool list as shown below.
public GoQSCViewBase (){
this.Document.Name = “Document”;
this.ReplaceMouseTool (typeof (GoToolContext), new GoQSCToolContext (this));
this.ReplaceMouseTool (typeof (GoToolDragging), new GoQSCToolDragging (this));
this.ReplaceMouseTool (typeof (GoToolLinkingNew), new GoQSCToolLinkingNew (this));
this.ReplaceMouseTool (typeof (GoToolRelinking), new GoQSCToolRelinking (this));
…// rest of constructor
// I removed the following override…
public override IList MouseMoveTools
{
get
{
if (m_MouseMoveTools == null)
{
m_MouseMoveTools = new ArrayList ();
m_MouseMoveTools.Add (new GoQSCToolTextBox (this));
m_MouseMoveTools.Add (new GoQSCToolLine (this));
m_MouseMoveTools.Add (new GoQSCToolRectangle (this));
m_MouseMoveTools.Add (new GoQSCToolEllipse (this));
m_MouseMoveTools.Add (new GoToolDragging (this)); //redundant?
m_MouseMoveTools.Add (new GoToolRubberBanding (this));
}
return m_MouseMoveTools;
}
}
I went ahead and removed the above override and added these lines to the constructor. Does this look like the correct thing to do?
base.MouseMoveTools.Add(new GoQSCToolTextBox(this));
base.MouseMoveTools.Add(new GoQSCToolLine(this));
base.MouseMoveTools.Add(new GoQSCToolRectangle(this));
base.MouseMoveTools.Add(new GoQSCToolEllipse(this));
Now, I am able to draw my links, but get no feedback as I am dragging as it used to work (only draws the link after mouse up on the destination port). If I try to delete the newly created link, it does not disappear from the view. If I then click on it, I get an exception: “Selected objects must belong to the view or its document”.
Starting to get nervous about upgrading. The reason I want to upgrade is that there is an annoying delay of about 15 - 20 seconds loading the Northwoods.Go.dll 2.1.2 from the new .net framework 2.0. Maybe there is a workaround for this? The 2.4 dll loads much quicker.
Any insight here would be appreciated.
Thanks - Craig

I don’t know what’s correct for your application, but the result will be different than what was originally coded, since those four new tools are being added at the end of the MouseMoveTools list instead of at the beginning as they were originally.
I agree that the override of GoView.MouseMoveTools was unnecessary, since those tools could have just been inserted at the start of the list.
You’ll need to debug your QSCToolLinkingNew tool to figure out what’s going on. If you just comment out the installation of that linking tool, does it sorta work? It depends on what that linking tool is supposed to do.

If I comment out the installation of the QSCToolLinkingNew tool, it “sorta” works as you guessed. I am able to draw one link at a time and correctly delete the link.
What our custom QSCToolLinkingNew tool code does is enable us to select multiple ports and do multiple links in one drag operation (using functions such as “PickNearestPort” and “CreateTemporaryPort”.)
I’ve tried reordering the list, replacing, using the overrride, not using the override, but I can’t seem to get this to work correctly.
What I am not understanding is why our old code worked at all. The MouseMoveTools override created a new arraylist of tools which did not include the tools we “replaced” in the constructor, but the tools we “replaced” in the constructor were getting used somehow. Shouldn’t the override have canceled the use of these tools since they were not part of the override? It appears that the “GoToolManager” was not using the list that the MouseMoveTools override was returning?

I verified in the old code that even though the MouseMoveTools property does not include the “QSCToolLinkingNew” object it still gets called from GoView? It appears that the override is working correctly in the new code (only the items in the override seem to be getting called).
After playing with this some more, I got rid of the “Replace” calls in the constructor and used the override exclusively to set the order. Everything now seems to work, except I still am getting no feedback until I “mouseup” on the target port. Once I do MouseUp all of my links are drawn and work correctly.
Do you have any idea why my links are not drawing during the MouseMove? When I start a drag on my GoPort it draws a horizontal line through the port and as I drag nothing else happens (should be seeing potential link(s) follow the cursor.
public void StartNewLink (PointF pt)
{
if (m_StartPorts.Count == 0)
return;
// By default, if the starting port is a valid source port, a new link is created
// with that port as the FROM port. Only if it is not a valid source port is the
// link drawn backwards, starting with the TO port.
this.Forwards = IsValidFromPort (m_StartPorts[0] as GoQSCPort);
m_TmpStartPorts = new GoPort[m_StartPorts.Count];
m_TmpEndPorts = new GoPort[m_StartPorts.Count];
m_TmpLinks = new GoLink[m_StartPorts.Count];
for (int i = 0; i < m_StartPorts.Count; i++)
{
GoQSCPort port = m_StartPorts as GoQSCPort;
if (this.Forwards)
{
m_TmpStartPorts = CreateTemporaryPort (port, port.GoObject.Center, false, false);
m_TmpEndPorts = CreateTemporaryPort (port, pt, true, true);
m_TmpLinks = CreateTemporaryLink (m_TmpStartPorts, m_TmpEndPorts);
}
else
{
m_TmpStartPorts = CreateTemporaryPort (port, port.GoObject.Center, true, false);
m_TmpEndPorts = CreateTemporaryPort (port, pt, false, true);
m_TmpLinks = CreateTemporaryLink (m_TmpEndPorts, m_TmpStartPorts);
}
}
this.View.Cursor = new Cursor (GetType (), “Cursors.Pen.cur”);
}
///


/// This method is called by to find the nearest
/// valid ports and adjust the temporary links according to where the given point is.
/// #GO: GoToolLinking::DoLinking
///

/// The current mouse point.
public override void DoLinking (PointF pt)
{
GoQSCPort portNearest = null;
RectangleF newrect;
base.DoLinking(pt);
for (int i = 0; i < m_StartPorts.Count; i++)
{
if (m_TmpEndPorts == null)
continue;
GoObject tempObj = m_TmpEndPorts.GoObject;

if (tempObj == null)
continue;
GoPort tempPort = tempObj as GoPort;
if (i == 0)
portNearest = PickNearestPort (pt, m_StartPorts[0] as GoQSCPort);
else
{
portNearest = PickNextValidPort( portNearest, m_StartPorts as GoQSCPort );
}
if (portNearest != null)
{
GoObject pobj = portNearest.GoObject;

if (pobj == null)
continue;
GoPort p = pobj as GoPort;

if (p != null)
{
// Make the temporary port act like the real one it might be connected to
if (tempPort != null)
{
tempPort.FromSpot = p.FromSpot;
tempPort.ToSpot = p.ToSpot;
tempPort.PortObject = p.PortObject;
}
newrect = p.Bounds;
}
else
{
if (tempPort != null)
{
tempPort.FromSpot = GoObject.NoSpot;
tempPort.ToSpot = GoObject.NoSpot;
tempPort.PortObject = null;
}
newrect = pobj.Bounds;
}
}
else
{
if (tempPort != null)
{
tempPort.FromSpot = GoObject.NoSpot;
tempPort.ToSpot = GoObject.NoSpot;
tempPort.PortObject = null;
}
newrect = new RectangleF (pt, new SizeF ());
}
tempObj.Bounds = newrect;
}
}

The tool might be in the GoView.MouseDownTools list, if it isn’t in the MouseMoveTools list or the MouseUpTools list.
I took a quick look at your code, but am unable to see anything suspicious about it.

It appears to me that “CreateTemporaryLink” is not working as it was in the previous version. We are running the exact same code, yet the temporary link is not being drawn. Did anything change there?

Code that was working perfectly in the previous version no longer works and I have spent many hours trying to fix it. As far as I can tell, the issue is something under the Go hood that I have no access to. The support resolution is to “take a quick look” and give up? I am completely frustrated. What other support options do I have? It would be nice if someone could figure out what changed in the new version and how to fix it.

Well, since I don’t have access to all of your code, it’s equally hard for me to figure out what might be relevant. But it’s good that you continue to talk about it, since that might give me some more ideas. For example, it’s useful to mention that the problem seems to be in CreateTemporaryLink.
Perhaps the problem is that you have some code in your link constructor that needs to execute in order for the link to be visible. One difference between 2.1 and 2.5 (the current version) is that CreateTemporaryLink now makes a copy of GoView.NewLinkPrototype, instead of creating an instance of the GoView.NewLinkClass. (The same is true for GoView.CreateLink.)

Thanks for the information.
I’d be glad to send you any relevant code if it would help. You already have the code for StartNewLink() where CreateTemporaryLink is called and DoLinking(). I have stepped through this a dozen times and can not figure out what the problem is. I don’t see anything in my link constructor of interest (below).
public GoQSCLink (GoQSCViewBase goQSCView)
{
m_GoQSCView = goQSCView;
this.Movable = false;
this.Copyable = false;
m_GoQSCView.Document.Changed += new GoChangedEventHandler (OnDocumentChanged);
m_GoQSCView.LinkCreated += new GoSelectionEventHandler (OnLinkCreated);
}

Whoa – why does the code add a GoDocument.Changed event handler and a GoView event handler every time you construct a link? That would mean a document with a thousand links would be calling that method a thousand times every time there was any change in the document!
Actually, that’s not the default constructor for GoQSCLink. Presumably there is one – what does it do?
Furthermore, is “m_GoQSCView” declared [NonSerialized]? It’s highly unusual to have a reference from a document object to the view, and it can’t be serialized if you want copy-and-paste to work.
Also, what does OnDocumentChanged actually do?
Is there any code that executes when the GoQSCLink is copied (overrides of CopyObject or CopyChildren)?

Yes I agree that the OnDocumentChanged event handler in every link is bogus. This could explain some performance issues I have been seeing! This code should be in the view. The nodes do the same thing…don’t ask me why it was done like this. I have wanted to change it for a while.
What the OnDocumentChanged event handler does is check if the link has been deleted and then unhook from the underlying business object…
// If this link was deleted
if (evt != null && evt.Hint == GoLayer.RemovedObject && evt.GoObject == this)
… disconnect the in business object “net”
There is no default constructor for the GoQSCLink, only the one with the goQSCView argument. There is also no override for CopyObject or CopyChildren in the link.
m_GoQQSCView is not declared [NonSerialized] but copy and paste works.

It sounds like your OnDocumentChanged method is trying to do the right thing, but that it shouldn’t be a method of a GoObject, but of the document or view or Form or App. You can easily check the type of the evt.GoObject:

GoQSCLink link = evt.GoObject as GoQSCLink;

if (link != null) { ...

} else {

GoQSCNode node = evt.GoObject as GoQSCNode; // or whatever node type you have...

if (node != null) { ... }

}

BTW, you don't need an override of CopyObject or CopyChildren unless you have added fields to your class that require changing after the object is cloned by calling MemberwiseClone().

I'm surprised that copy and paste works. Hmmm.

Thanks for the feedback Walter. With your help, I am still chipping away at this…
Our code overrides “CopySelection”, “EditCopy” and “EditPaste” in the view and delegates most of the work to the underlying objects. It is funky but it works.
I have been digging around trying to find a different between the temporary links.
I noticed that if I look at the link returned from CreateTemporaryLink in the watch window for both the working and non working versions and dig down to the GoObject.Bounds.IsEmpty property, there is a difference. The “good” version returns IsEmpty as false while the “bad” version returns IsEmpty as true. If you look at the override for DoLinking above, we are setting the “Bounds” property on the m_TmpEndPorts (which is false in both cases).
I am also wondering if the temporary link might be getting created on the wrong layer so we can’t see it. I have tried to add the temporary link to the “links layer” but it complains that it is already in a layer (the default layer?)

While we are talking about unusual code, could you explain what the following code is doing:

What is the declaration for “m_StartPorts”? How can it both be a collection and a GoQSCPort, unless GoQSCPort is a collection of GoPorts? If the temporary link is being created with no ports, I can see how the link’s stroke might be empty, thereby giving it a Bounds that is empty.
Why is the code trying to create a whole bunch of temporary links and temporary ports, anyway?
GoToolLinking.CreateTemporaryLink, as documented, adds the temporary link to the default layer of the view, not in a document layer.

You have a good eye. Sorry, this line is a typo:
GoQSCPort port = m_StartPorts as GoQSCPort;
The actual code is this:
GoQSCPort port = m_StartPorts as GoQSCPort;
I have no idea where the “” went when I copied it originally…strange…I don’t even remember experimenting with this function. Everything else looks correct except for the call to the base class in DoLinking (that I do remember adding that as an experiment at one point - didn’t make any difference).
Anyway, the goal of this code is to enable the user to select multiple ports on a node and create multiple links to another node with one mouse drag. It works pretty cool actually (when it works). The multiple links are created when we do the mouse up, it is just the visual feedback during the drag that is missing.
If more than one start port is selected, it is supposed to create multiple temporary links drawn from the source ports that all converge on the mouse cursor until the port gravity takes over when dragged near valid destination ports. Then we will see where all of the multiple links will be created when we mouse up.
The temporary links do have reference to ports. We just don’t see them for some reason.