protected override void OnDragEnter(DragEventArgs drgevent) { base.OnDragEnter(drgevent); int hvoDstOwner; // dummies, we just want to set the Effect property of drgevent. int flidDst; int ihvoDstStart; ObjectDragInfo odi = TestDropEffects(drgevent, out hvoDstOwner, out flidDst, out ihvoDstStart); }
protected override void OnDragDrop(DragEventArgs drgevent) { base.OnDragDrop(drgevent); int hvoDstOwner; int flidDst; int ihvoDstStart; ObjectDragInfo odi = TestDropEffects(drgevent, out hvoDstOwner, out flidDst, out ihvoDstStart); if (drgevent.Effect == DragDropEffects.None) { return; } // Todo JohnT: verify that m_slice is the last slice in the representation of flid. Slice.ContainingDataTree.Cache.MoveOwningSequence(odi.HvoSrcOwner, odi.FlidSrc, odi.IhvoSrcStart, odi.IhvoSrcEnd, hvoDstOwner, flidDst, ihvoDstStart); }
/// <summary> /// Preliminary version of mouse down handles expansion and contraction. /// Todo: /// - Scroll appropriately to show as much as possible of what was expanded. /// - drag and drop effects. /// - double-click on label also toggles expansion. /// </summary> protected override void OnMouseDown(MouseEventArgs meArgs) { //in light of what JT says below, we need to explicitly tell the slice that //we were clicked on, because we cannot count on a normal Click event //which we would normally just subscribe to, as we do with the slice editor controls. Slice.OnTreeNodeClick(this, meArgs); // The documentation says we should call the base class. Not doing so means that // mouse down handlers can't be attached to this class by delegation. // However, the base class implementation has a catastrophic side effect: it causes // this control to be selected, in a sense that causes it to be scrolled into // view every time a lazy slice is expanded into a real one. This is the first // successful way I (JT) found to defeat this behavior, and I tried many. //base.OnMouseDown(meArgs); if (meArgs.Button.Equals(MouseButtons.Right) || (ShowingContextIcon && meArgs.X < 20)) { //begin test (JDH) Point p = new Point(meArgs.X, meArgs.Y); if (Slice.HandleMouseDown(p)) { return; } //end test } // Enhance JohnT: Could we find a better label that shows more clearly what is being moved? int hvoSrcOwner; int flidSrc; int ihvoSrcStart; if (!Slice.GetSeqContext(out hvoSrcOwner, out flidSrc, out ihvoSrcStart)) { return; // If we can't identify an object to move, don't do a drag. } ObjectDragInfo objinfo = new ObjectDragInfo(hvoSrcOwner, flidSrc, ihvoSrcStart, ihvoSrcStart, Slice.Label); DataObject dataobj = new DataObject(objinfo); // Initiate a drag/drop operation. Currently we only support move. // Enhance JohnT: Also support Copy. DoDragDrop(dataobj, DragDropEffects.Move); }
protected override void OnDragDrop(DragEventArgs drgevent) { base.OnDragDrop(drgevent); int hvoDstOwner; int flidDst; int ihvoDstStart; ObjectDragInfo odi = TestDropEffects(drgevent, out hvoDstOwner, out flidDst, out ihvoDstStart); if (drgevent.Effect == DragDropEffects.None) { return; } // Todo JohnT: verify that m_slice is the last slice in the representation of flid. FdoCache cache = Slice.ContainingDataTree.Cache; UndoableUnitOfWorkHelper.Do("Undo Move Item", "Redo Move Item", cache.ActionHandlerAccessor, () => { cache.DomainDataByFlid.MoveOwnSeq(odi.HvoSrcOwner, odi.FlidSrc, odi.IhvoSrcStart, odi.IhvoSrcEnd, hvoDstOwner, flidDst, ihvoDstStart); }); }
/// <summary> /// Test whether we can drop the information indicated by the drgevent onto this. /// Currently this is possible if /// 1. The drag event's data is an ObjectDragInfo /// 2. It is valid for those objects to be moved to a position just after the object of which /// the destination slice is a part, in the lowest level sequence of which it is a part. /// drgevent.Effect is set to Move or None to indicate the result. If successful, returns an ObjectDragInfo /// and the place to put the new objects. /// (Note: the ihvoDstStart returned is meaningless if the property is a collection.) /// /// Move is valid under the following conditions: /// 1. Must not violate signature. Signature is checked if destination property is different from source. /// 2. Must not create circularity of ownership. This is checked if destination object is different from source. /// 3. Must result in actual movement. This is checked if destination and source object and flid are the same. /// This case always fails if the property is a collection, also if it is a sequence and nothing would change. /// </summary> /// <param name="drgevent">Passed so Effect can be set.</param> /// <param name="hvoDstOwner">Object to move things to</param> /// <param name="flidDst">Property to move to.</param> /// <param name="ihvoDstStart">Place to put them (if sequence).</param> /// <returns></returns> private ObjectDragInfo TestDropEffects(DragEventArgs drgevent, out int hvoDstOwner, out int flidDst, out int ihvoDstStart) { ObjectDragInfo odi = (ObjectDragInfo)drgevent.Data.GetData(typeof(ObjectDragInfo)); drgevent.Effect = DragDropEffects.None; // default hvoDstOwner = 0; // not used unless we get to GetSeqContext call, but compiler demands we set them. flidDst = 0; ihvoDstStart = 0; if (odi != null) { // Enhance JohnT: options to allow dragging onto this object, putting the dragged object into // one of its owning properties. // Try to drag the object after 'this' in the relevant property. if (Slice.GetSeqContext(out hvoDstOwner, out flidDst, out ihvoDstStart)) { ihvoDstStart++; // Insert after the present object (if a sequence). if (OkToMove(hvoDstOwner, flidDst, ihvoDstStart, odi)) { drgevent.Effect = DragDropEffects.Move; return(odi); } } // See if the first child is a sequence we could insert at the start of. XmlNode firstChild = Slice.ConfigurationNode.FirstChild; if (firstChild != null && firstChild.Name == "seq") { hvoDstOwner = Slice.Object.Hvo; flidDst = (int)Slice.ContainingDataTree.Cache.MetaDataCacheAccessor.GetFieldId2((uint)Slice.Object.ClassID, firstChild.Attributes["field"].Value, true); ihvoDstStart = 0; if (OkToMove(hvoDstOwner, flidDst, ihvoDstStart, odi)) { drgevent.Effect = DragDropEffects.Move; return(odi); } } } return(odi); }
/// <summary> /// Preliminary version of mouse down handles expansion and contraction. /// Todo: /// - Scroll appropriately to show as much as possible of what was expanded. /// - drag and drop effects. /// - double-click on label also toggles expansion. /// </summary> protected override void OnMouseDown(MouseEventArgs meArgs) { //in light of what JT says below, we need to explicitly tell the slice that //we were clicked on, because we cannot count on a normal Click event //which we would normally just subscribe to, as we do with the slice editor controls. Slice.OnTreeNodeClick(this, meArgs); // The documentation says we should call the base class. Not doing so means that // mouse down handlers can't be attached to this class by delegation. // However, the base class implementation has a catastrophic side effect: it causes // this control to be selected, in a sense that causes it to be scrolled into // view every time a lazy slice is expanded into a real one. This is the first // successful way I (JT) found to defeat this behavior, and I tried many. //base.OnMouseDown(meArgs); if (meArgs.Button.Equals(MouseButtons.Right) || (ShowingContextIcon && meArgs.X < 20)) { //begin test (JDH) Point p = new Point(meArgs.X,meArgs.Y); if (Slice.HandleMouseDown(p)) { return; } //end test } // Enhance JohnT: Could we find a better label that shows more clearly what is being moved? int hvoSrcOwner; int flidSrc; int ihvoSrcStart; if (!Slice.GetSeqContext(out hvoSrcOwner, out flidSrc, out ihvoSrcStart)) return; // If we can't identify an object to move, don't do a drag. ObjectDragInfo objinfo = new ObjectDragInfo(hvoSrcOwner, flidSrc, ihvoSrcStart, ihvoSrcStart, Slice.Label); DataObject dataobj = new DataObject(objinfo); // Initiate a drag/drop operation. Currently we only support move. // Enhance JohnT: Also support Copy. DoDragDrop(dataobj, DragDropEffects.Move); }
public bool OkToMove(int hvoDstOwner, int flidDst, int ihvoDstStart, ObjectDragInfo odi) { CheckDisposed(); FDO.FdoCache cache = Slice.ContainingDataTree.Cache; ICmObjectRepository repo = cache.ServiceLocator.GetInstance<ICmObjectRepository>(); if (flidDst == odi.FlidSrc) { // Verify that it is not a no-operation. if (hvoDstOwner == odi.HvoSrcOwner) { // Same property of same object. If it's a collection, disable. CellarPropertyType fieldType = (CellarPropertyType)cache.DomainDataByFlid.MetaDataCache.GetFieldType((int)flidDst); // We can't drag it to the position it's already at; that's no change. We also can't drag it // to the position one greater: that amounts to trying to place it after itself, which (after // removing it from before itself) amounts to a no-operation. if (fieldType == CellarPropertyType.OwningSequence && ihvoDstStart != odi.IhvoSrcStart && ihvoDstStart != odi.IhvoSrcStart + 1) { // It's a sequence and the target and source positions are different, so we can do it. return true; } } else { // Different objects; need to verify no circular ownership involved. for (int ihvo = odi.IhvoSrcStart; ihvo <= odi.IhvoSrcEnd; ihvo++) { int hvo = cache.DomainDataByFlid.get_VecItem(odi.HvoSrcOwner, odi.FlidSrc, ihvo); // See if hvoDstOwner is owned by hvo ICmObject obj2 = repo.GetObject(hvoDstOwner); // loop from hvo2 to root owner of hvo2. If hvo2 or any of its owners is hvo, // we have a problem. while (obj2 != null) { if (hvo == obj2.Hvo) return false; // circular ownership, can't drop. obj2 = obj2.Owner; } } return true; } } else { // Different property, check signature. IFwMetaDataCache mdc = cache.DomainDataByFlid.MetaDataCache; int luclid = mdc.GetDstClsId((int) flidDst); for (int ihvo = odi.IhvoSrcStart; ihvo <= odi.IhvoSrcEnd; ihvo++) { int hvo = cache.DomainDataByFlid.get_VecItem(odi.HvoSrcOwner, odi.FlidSrc, ihvo); int cls = repo.GetObject(hvo).ClassID; while (cls != 0 && cls != luclid) { cls = mdc.GetBaseClsId(cls); } if (cls == 0) return false; // wrong signature, can't drop. } // All sigs OK, allow drop. return true; } // If none of those cases is OK, can't do it. return false; }
/// <summary> /// Preliminary version of mouse down handles expansion and contraction. /// Todo: /// - Scroll appropriately to show as much as possible of what was expanded. /// - drag and drop effects. /// - double-click on label also toggles expansion. /// </summary> protected override void OnMouseDown(MouseEventArgs meArgs) { //in light of what JT says below, we need to explicitly tell the slice that //we were clicked on, because we cannot count on a normal Click event //which we would normally just subscribe to, as we do with the slice editor controls. Slice.OnTreeNodeClick(this, meArgs); // The documentation says we should call the base class. Not doing so means that // mouse down handlers can't be attached to this class by delegation. // However, the base class implementation has a catastrophic side effect: it causes // this control to be selected, in a sense that causes it to be scrolled into // view every time a lazy slice is expanded into a real one. This is the first // successful way I (JT) found to defeat this behavior, and I tried many. //base.OnMouseDown(meArgs); if (meArgs.Button.Equals(MouseButtons.Right) || (ShowingContextIcon && meArgs.X < 20)) { //begin test (JDH) Point p = new Point(meArgs.X, meArgs.Y); if (Slice.HandleMouseDown(p)) { return; } //end test // // Setup the context menu every time, because it contains information about // // item positions that can be invalidated by inserting items, etc. // SetupContextMenu(); // return; } int xp = meArgs.X; // xpText is the left side of the tree label. int xpText = kdxpLeftMargin + kdxpIndDist + Slice.Indent * kdxpIndDist; // If we are over the +/- box... // But, we never are in the current way all this works (see LT-2643, apparently some slices, such // as the summary slice for a LexSense, think they are collapsed and can be expanded. // if (xp < xpText && xp >= xpText - kdxpIndDist) // { // // Handle label expansion and contraction. // if (Slice.Expansion != DataTree.TreeItemState.ktisFixed) // { // int iSlice = Slice.Parent.Controls.IndexOf(Slice); // ToggleExpansionAndScroll(iSlice); // } // } // else // { // Enhance JohnT: Could we find a better label that shows more clearly what is being moved? int hvoSrcOwner; int flidSrc; int ihvoSrcStart; if (!Slice.GetSeqContext(out hvoSrcOwner, out flidSrc, out ihvoSrcStart)) { return; // If we can't identify an object to move, don't do a drag. } ObjectDragInfo objinfo = new ObjectDragInfo(hvoSrcOwner, flidSrc, ihvoSrcStart, ihvoSrcStart, Slice.Label); DataObject dataobj = new DataObject(objinfo); // Initiate a drag/drop operation. Currently we only support move. // Enhance JohnT: Also support Copy. DoDragDrop(dataobj, DragDropEffects.Move); // } }
/// <summary> /// Return whether it is OK to move the objects indicated by odi to the specified destination. /// </summary> /// <param name="hvoDstOwner"></param> /// <param name="flidDst"></param> /// <param name="ihvoDstStart"></param> /// <param name="odi"></param> /// <returns></returns> public bool OkToMove(int hvoDstOwner, int flidDst, int ihvoDstStart, ObjectDragInfo odi) { CheckDisposed(); FDO.FdoCache cache = Slice.ContainingDataTree.Cache; if (flidDst == odi.FlidSrc) { // Verify that it is not a no-operation. if (hvoDstOwner == odi.HvoSrcOwner) { // Same property of same object. If it's a collection, disable. FieldType fieldType = cache.GetFieldType(flidDst); // We can't drag it to the position it's already at; that's no change. We also can't drag it // to the position one greater: that amounts to trying to place it after itself, which (after // removing it from before itself) amounts to a no-operation. if (fieldType == FieldType.kcptOwningSequence && ihvoDstStart != odi.IhvoSrcStart && ihvoDstStart != odi.IhvoSrcStart + 1) { // It's a sequence and the target and source positions are different, so we can do it. return(true); } } else { // Different objects; need to verify no circular ownership involved. for (int ihvo = odi.IhvoSrcStart; ihvo <= odi.IhvoSrcEnd; ihvo++) { int hvo = cache.GetVectorItem(odi.HvoSrcOwner, odi.FlidSrc, ihvo); // See if hvoDstOwner is owned by hvo int hvo2 = hvoDstOwner; // loop from hvo2 to root owner of hvo2. If hvo2 or any of its owners is hvo, // we have a problem. while (hvo2 != 0) { if (hvo == hvo2) { return(false); // circular ownership, can't drop. } hvo2 = cache.GetOwnerOfObject(hvo2); } } return(true); } } else { // Different property, check signature. IFwMetaDataCache mdc = cache.MetaDataCacheAccessor; uint luclid = mdc.GetDstClsId((uint)flidDst); for (int ihvo = odi.IhvoSrcStart; ihvo <= odi.IhvoSrcEnd; ihvo++) { int hvo = cache.GetVectorItem(odi.HvoSrcOwner, odi.FlidSrc, ihvo); uint cls = (uint)cache.GetClassOfObject(hvo); while (cls != 0 && cls != luclid) { cls = mdc.GetBaseClsId(cls); } if (cls == 0) { return(false); // wrong signature, can't drop. } } // All sigs OK, allow drop. return(true); } // If none of those cases is OK, can't do it. return(false); }
/// <summary> /// Preliminary version of mouse down handles expansion and contraction. /// Todo: /// - Scroll appropriately to show as much as possible of what was expanded. /// - drag and drop effects. /// - double-click on label also toggles expansion. /// </summary> protected override void OnMouseDown(MouseEventArgs meArgs) { //in light of what JT says below, we need to explicitly tell the slice that //we were clicked on, because we cannot count on a normal Click event //which we would normally just subscribe to, as we do with the slice editor controls. Slice.OnTreeNodeClick(this, meArgs); // The documentation says we should call the base class. Not doing so means that // mouse down handlers can't be attached to this class by delegation. // However, the base class implementation has a catastrophic side effect: it causes // this control to be selected, in a sense that causes it to be scrolled into // view every time a lazy slice is expanded into a real one. This is the first // successful way I (JT) found to defeat this behavior, and I tried many. //base.OnMouseDown(meArgs); if (meArgs.Button.Equals(MouseButtons.Right) || (ShowingContextIcon && meArgs.X < 20)) { //begin test (JDH) Point p = new Point(meArgs.X,meArgs.Y); if (Slice.HandleMouseDown(p)) { return; } //end test // // Setup the context menu every time, because it contains information about // // item positions that can be invalidated by inserting items, etc. // SetupContextMenu(); // return; } int xp = meArgs.X; // xpText is the left side of the tree label. int xpText = kdxpLeftMargin + kdxpIndDist + Slice.Indent * kdxpIndDist; // If we are over the +/- box... // But, we never are in the current way all this works (see LT-2643, apparently some slices, such // as the summary slice for a LexSense, think they are collapsed and can be expanded. // if (xp < xpText && xp >= xpText - kdxpIndDist) // { // // Handle label expansion and contraction. // if (Slice.Expansion != DataTree.TreeItemState.ktisFixed) // { // int iSlice = Slice.Parent.Controls.IndexOf(Slice); // ToggleExpansionAndScroll(iSlice); // } // } // else // { // Enhance JohnT: Could we find a better label that shows more clearly what is being moved? int hvoSrcOwner; int flidSrc; int ihvoSrcStart; if (!Slice.GetSeqContext(out hvoSrcOwner, out flidSrc, out ihvoSrcStart)) return; // If we can't identify an object to move, don't do a drag. ObjectDragInfo objinfo = new ObjectDragInfo(hvoSrcOwner, flidSrc, ihvoSrcStart, ihvoSrcStart, Slice.Label); DataObject dataobj = new DataObject(objinfo); // Initiate a drag/drop operation. Currently we only support move. // Enhance JohnT: Also support Copy. DoDragDrop(dataobj, DragDropEffects.Move); // } }