Exemplo n.º 1
0
        private void DragDropHandler(params object[] arguments)
        {
            ObjectNode toNode    = (ObjectNode)arguments[0];
            ObjectNode fromNode  = (ObjectNode)arguments[1];
            ObjectNode childNode = (ObjectNode)arguments[2];

            // Make sure the user has selected a valid source and destination for the operation.  It's illegal to move the node
            //		1.  To the root of the tree
            //		2.  From the root of the tree
            if (toNode == null || fromNode == null)
            {
                return;
            }

            // Don't allow for circular references.
            try
            {
                // Lock the tables needed for this operation.
                Debug.Assert(!ClientMarketData.AreLocksHeld);
                ClientMarketData.ObjectLock.AcquireReaderLock(CommonTimeout.LockWait);

                // It's critical that circular references aren't created, either by accident or design.  First, find the object
                // record associated with the destination node.
                ClientMarketData.ObjectRow parentRow = ClientMarketData.Object.FindByObjectId(toNode.ObjectId);
                if (parentRow == null)
                {
                    throw new Exception("This object has been deleted");
                }

                // This is the object that is being dragged.  Find the row
                ClientMarketData.ObjectRow childRow = ClientMarketData.Object.FindByObjectId(childNode.ObjectId);
                if (childRow == null)
                {
                    throw new Exception("This object has been deleted");
                }

                if (Shadows.Quasar.Common.Relationship.IsChildObject(childRow, parentRow))
                {
                    MessageBox.Show(this.TopLevelControl, "This would create a circular references.", "Quasar Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    return;
                }
            }
            catch (Exception exception)
            {
                // Write the error and stack trace out to the debug listener
                Debug.WriteLine(String.Format("{0}, {1}", exception.Message, exception.StackTrace));
            }
            finally
            {
                // Release table locks.
                if (ClientMarketData.ObjectLock.IsReaderLockHeld)
                {
                    ClientMarketData.ObjectLock.ReleaseReaderLock();
                }
                Debug.Assert(!ClientMarketData.AreLocksHeld);
            }

            // Any commands created below will be constructed in this object and sent to the server for execution.
            RemoteBatch remoteBatch = new RemoteBatch();

            // Change the default model of an account.  When the destination is an account group, account or sub account and the
            // source is a model, a command will be constructed to change the default model.
            if (toNode.ObjectTypeCode == ObjectType.Account && dragNode.ObjectTypeCode == ObjectType.Model)
            {
                try
                {
                    // Lock the tables needed for this operation.
                    Debug.Assert(!ClientMarketData.AreLocksHeld);
                    ClientMarketData.AccountLock.AcquireReaderLock(CommonTimeout.LockWait);

                    // Find the account used, throw an error if it's been deleted.
                    ClientMarketData.AccountRow accountRow;
                    if ((accountRow = ClientMarketData.Account.FindByAccountId(toNode.ObjectId)) == null)
                    {
                        throw new Exception("This account has been deleted");
                    }

                    // Construct a command to change the default model associated with the account.
                    RemoteAssembly remoteAssembly = remoteBatch.Assemblies.Add("Service.Core");
                    RemoteType     remoteType     = remoteAssembly.Types.Add("Shadows.WebService.Core.Account");
                    RemoteMethod   remoteMethod   = remoteType.Methods.Add("Update");
                    remoteMethod.Parameters.Add("rowVersion", accountRow.RowVersion);
                    remoteMethod.Parameters.Add("accountId", accountRow.AccountId);
                    remoteMethod.Parameters.Add("modelId", dragNode.ObjectId);
                }
                catch (Exception exception)
                {
                    // Write the error and stack trace out to the debug listener
                    Debug.WriteLine(String.Format("{0}, {1}", exception.Message, exception.StackTrace));
                }
                finally
                {
                    // Release table locks.
                    if (ClientMarketData.AccountLock.IsReaderLockHeld)
                    {
                        ClientMarketData.AccountLock.ReleaseReaderLock();
                    }
                    Debug.Assert(!ClientMarketData.AreLocksHeld);
                }
            }
            else
            {
                // If we made it here, the drag-and-drop is interpreted as a command to move a child from one parent to another.
                try
                {
                    // Lock the tables needed for this operation.
                    Debug.Assert(!ClientMarketData.AreLocksHeld);
                    ClientMarketData.ObjectTreeLock.AcquireReaderLock(CommonTimeout.LockWait);

                    // Extract the primary identifiers from the user interface nodes.
                    int fromId  = fromNode.ObjectId;
                    int toId    = toNode.ObjectId;
                    int childId = dragNode.ObjectId;

                    // Find the object in the data model and make sure it still exists.
                    ClientMarketData.ObjectTreeRow objectTreeRow = ClientMarketData.ObjectTree.FindByParentIdChildId(fromNode.ObjectId, dragNode.ObjectId);
                    if (objectTreeRow == null)
                    {
                        throw new Exception("This relationship has been deleted by someone else.");
                    }

                    // Moving a child object from one parent to another must be accomplished as a transaction.  Otherwise, an
                    // orhpan object will be created if the operation fails midway through.
                    RemoteTransaction remoteTransaction = remoteBatch.Transactions.Add();
                    RemoteAssembly    remoteAssembly    = remoteBatch.Assemblies.Add("Service.Core");
                    RemoteType        remoteType        = remoteAssembly.Types.Add("Shadows.WebService.Core.ObjectTree");

                    // Construct a command delete the old parent relation.
                    RemoteMethod deleteObjectTree = remoteType.Methods.Add("Delete");
                    deleteObjectTree.Transaction = remoteTransaction;
                    deleteObjectTree.Parameters.Add("rowVersion", objectTreeRow.RowVersion);
                    deleteObjectTree.Parameters.Add("parentId", fromId);
                    deleteObjectTree.Parameters.Add("childId", childId);

                    // Construct a command insert a new parent relation.
                    RemoteMethod insertObjectTree = remoteType.Methods.Add("Insert");
                    insertObjectTree.Transaction = remoteTransaction;
                    insertObjectTree.Parameters.Add("parentId", toId);
                    insertObjectTree.Parameters.Add("childId", childId);
                }
                catch (Exception exception)
                {
                    // Write the error and stack trace out to the debug listener
                    Debug.WriteLine(String.Format("{0}, {1}", exception.Message, exception.StackTrace));
                }
                finally
                {
                    // Release table locks.
                    if (ClientMarketData.ObjectTreeLock.IsReaderLockHeld)
                    {
                        ClientMarketData.ObjectTreeLock.ReleaseReaderLock();
                    }
                    Debug.Assert(!ClientMarketData.AreLocksHeld);
                }
            }

            // If the command batch was built successfully, then execute it.
            if (remoteBatch != null)
            {
                try
                {
                    // Call the web server to rename the object on the database.  Note that this method must be called when there are
                    // no locks to prevent deadlocking.  That is why it appears in it's own 'try/catch' block.
                    ClientMarketData.Execute(remoteBatch);
                }
                catch (BatchException batchException)
                {
                    // Display each error in the batch.
                    foreach (RemoteException remoteException in batchException.Exceptions)
                    {
                        MessageBox.Show(remoteException.Message, "Quasar Error");
                    }
                }
            }
        }
Exemplo n.º 2
0
        /// <summary>
        /// Event handler for changing the name of a label.
        /// </summary>
        /// <param name="sender">The window control that generated the 'LabelEdit' event.</param>
        /// <param name="e">Event Parameters used to control the actions taken by the event handler.</param>
        private void treeView_AfterLabelEdit(object sender, System.Windows.Forms.NodeLabelEditEventArgs e)
        {
            // The TreeView has a bug in it: if you leave the edit mode without typing anything, the returned text of the control
            // will be an empty string. Since we don't want to bother the server or the user with this nonsense, we'll filter out
            // the possiblity here.
            if (e.Label == null)
            {
                e.CancelEdit = true;
                return;
            }

            // Extract the object's properties from the node.
            ObjectNode objectNode = (ObjectNode)e.Node;

            // This command batch is constructed below and sent to the server for execution.
            RemoteBatch remoteBatch = new RemoteBatch();

            // This will insure that table locks are cleaned up.
            try
            {
                // Lock the table
                Debug.Assert(!ClientMarketData.AreLocksHeld);
                ClientMarketData.ObjectLock.AcquireReaderLock(CommonTimeout.LockWait);

                // Find the object in the data model and make sure it still exists.
                ClientMarketData.ObjectRow objectRow = ClientMarketData.Object.FindByObjectId(objectNode.ObjectId);
                if (objectRow == null)
                {
                    throw new Exception("This object has been deleted.");
                }

                // Construct a command to rename the object.
                RemoteAssembly remoteAssembly = remoteBatch.Assemblies.Add("Service.Core");
                RemoteType     remoteType     = remoteAssembly.Types.Add("Shadows.WebService.Core.Object");
                RemoteMethod   remoteMethod   = remoteType.Methods.Add("Update");
                remoteMethod.Parameters.Add("rowVersion", objectRow.RowVersion);
                remoteMethod.Parameters.Add("objectId", objectRow.ObjectId);
                remoteMethod.Parameters.Add("name", e.Label);
            }
            catch (Exception exception)
            {
                // Write the error and stack trace out to the debug listener
                Debug.WriteLine(String.Format("{0}, {1}", exception.Message, exception.StackTrace));

                // Cancel the tree operation if we can't execute the command.  The text in the tree control will revert to the
                // previous value.
                e.CancelEdit = true;
            }
            finally
            {
                // Release table locks.
                if (ClientMarketData.ObjectLock.IsReaderLockHeld)
                {
                    ClientMarketData.ObjectLock.ReleaseReaderLock();
                }
                Debug.Assert(!ClientMarketData.AreLocksHeld);
            }

            // If the command batch was built successfully, then execute it.  If any part of it should fail, cancel the edit and
            // display the server errors.
            if (remoteBatch != null)
            {
                try
                {
                    // Call the web server to rename the object on the database.  Note that this method must be called when there are
                    // no locks to prevent deadlocking.  That is why it appears in it's own 'try/catch' block.
                    ClientMarketData.Execute(remoteBatch);
                }
                catch (BatchException batchException)
                {
                    // Undo the editing action.  This will restore the name of the object to what it was before the operation.
                    e.CancelEdit = true;

                    // Display each error in the batch.
                    foreach (RemoteException remoteException in batchException.Exceptions)
                    {
                        MessageBox.Show(remoteException.Message, "Quasar Error");
                    }
                }
            }
        }
Exemplo n.º 3
0
 /// <summary>
 /// Creates a structure that can be used to open or operate on a generic object.
 /// </summary>
 /// <param name="objectNode">A node in the TreeView that represents an object in the Database.</param>
 /// <returns>A structure that specifies what object to view, what type of object it is, and any optional
 /// parameters that might be needed to open the object.</returns>
 private ObjectArgs CreateObjectArgs(ObjectNode objectNode)
 {
     // The returned value represents an object selected from the Folder List.  It has all the parameters needed to
     // open a reader.
     return(new ObjectArgs(objectNode.ObjectTypeCode, objectNode.ObjectId, objectNode.Name));
 }
Exemplo n.º 4
0
        /// <summary>
        /// Recursively updates the TreeView control with a new tree structure.
        /// </summary>
        /// <param name="targetNodeCollection">The target tree for the changes.</param>
        /// <param name="sourceNodeCollection">The source tree containing the new structure.</param>
        private void RecurseRefresh(TreeNodeCollection targetNodeCollection, TreeNodeCollection sourceNodeCollection)
        {
            // The main idea here is to run through all the nodes looking for Adds, Deletes and Updates.  When we find a
            // Node that shouldn't be in the structure, it's deleted from the tree.  Since the tree is made up of linked
            // lists, we can't rightly delete the current link in the list.  For this reason we need to use the index into
            // the list for spanning the structure instead of the collection operations.  When we find an element that
            // needs to be removed, we can delete it and the index will get us safely to the next element in the list. The
            // first loop scans the list already in the TreeView structure.
            for (int targetIndex = 0; targetIndex < targetNodeCollection.Count; targetIndex++)
            {
                // Get a reference to the current node in the target (older) list of nodes.
                ObjectNode childTargetNode = (ObjectNode)targetNodeCollection[targetIndex];

                // If we don't find the target (older) element in the source (newer) list, it will be deleted.
                bool found = false;

                // Cycle through all of the source (newer) elements looking for changes and removing any elements that
                // exist in both lists.
                for (int sourceIndex = 0; sourceIndex < sourceNodeCollection.Count; sourceIndex++)
                {
                    // Get a reference to the current node in the source (newer) list of nodes.
                    ObjectNode childSourceNode = (ObjectNode)sourceNodeCollection[sourceIndex];

                    // If the elements are equal (as defined by the key element), then recurse into the structure looking
                    // for changes to the children.  After that, check the Node for any changes since it was added to the
                    // tree.
                    if (childTargetNode.ObjectId == childSourceNode.ObjectId)
                    {
                        // Recurse down into the tree structures bringing all the children in sync with the new structure.
                        RecurseRefresh(childTargetNode.Nodes, childSourceNode.Nodes);

                        // Check the Nodes Name.  Update it if there's a change.
                        if (childTargetNode.Text != childSourceNode.Name)
                        {
                            childTargetNode.Text = childSourceNode.Name;
                        }

                        // At this point, we've checked all the children and applied any changes to the node.  Remove it
                        // from the list.  Any elements left in the source list are assumed to be new members and will be
                        // added to the tree structure.  That's why it's important to remove the ones already in the tree.
                        sourceNodeCollection.Remove(childSourceNode);
                        sourceIndex--;

                        // This will signal the target loop that this element still exists in the structure.  If it isn't
                        // found, it'll be deleted.
                        found = true;
                    }
                }

                // If the target (older) element isn't found in the source (newer) tree, it's deleted.
                if (!found)
                {
                    targetNodeCollection.Remove(childTargetNode);
                    targetIndex--;
                }
            }

            // Any element that doesn't already exist in the target (older) tree, is copied from the source (newer) tree,
            // along with all it's children.
            for (int nodeIndex = 0; nodeIndex < sourceNodeCollection.Count; nodeIndex++)
            {
                ObjectNode objectNode = (ObjectNode)sourceNodeCollection[nodeIndex--];
                sourceNodeCollection.Remove(objectNode);
                targetNodeCollection.Add(objectNode);
            }
        }
Exemplo n.º 5
0
 /// <summary>
 /// Populates the Tree Control with data collected in the initialization thread.
 /// </summary>
 /// <param name="objectNode">Contains a hierarchical organization of objects.</param>
 private void RefreshTree(ObjectNode objectNode)
 {
     // This will recursively reconstruct the tree from the relational data gathered from the background thread.
     RecurseRefresh(this.treeView.Nodes, objectNode.Nodes);
 }
Exemplo n.º 6
0
        /// <summary>
        /// This procedure is used to update the TreeView control from the background.
        /// </summary>
        private void FolderListThread(params object[] argument)
        {
            // This node acts as the root that we'll use to build the tree folder list tree.  It will eventually be
            // passed back to the main thread and into the TreeView control.
            ObjectNode rootNode = new ObjectNode();

            try
            {
                // Lock all the tables that we'll reference while building a blotter document.
                Debug.Assert(!ClientMarketData.AreLocksHeld);
                ClientMarketData.FolderLock.AcquireReaderLock(CommonTimeout.LockWait);
                ClientMarketData.LoginLock.AcquireReaderLock(CommonTimeout.LockWait);
                ClientMarketData.ObjectLock.AcquireReaderLock(CommonTimeout.LockWait);
                ClientMarketData.ObjectTreeLock.AcquireReaderLock(CommonTimeout.LockWait);

                // Recursively build the Tree View from the user's folder.
                ClientMarketData.LoginRow loginRow = ClientMarketData.Login.FindByLoginId(ClientPreferences.LoginId);
                if (loginRow != null && !loginRow.IsFolderIdNull())
                {
                    ClientMarketData.FolderRow folderRow = ClientMarketData.Folder.FindByFolderId(loginRow.FolderId);
                    rootNode.Nodes.Add(new ObjectNode(folderRow.ObjectRow));
                }
            }
            catch (Exception e)
            {
                // Catch the most general error and send it to the debug console.
                Debug.WriteLine(e.Message);
            }
            finally
            {
                // Release the tables used to build the folder list.
                if (ClientMarketData.FolderLock.IsReaderLockHeld)
                {
                    ClientMarketData.FolderLock.ReleaseReaderLock();
                }
                if (ClientMarketData.LoginLock.IsReaderLockHeld)
                {
                    ClientMarketData.LoginLock.ReleaseReaderLock();
                }
                if (ClientMarketData.ObjectLock.IsReaderLockHeld)
                {
                    ClientMarketData.ObjectLock.ReleaseReaderLock();
                }
                if (ClientMarketData.ObjectTreeLock.IsReaderLockHeld)
                {
                    ClientMarketData.ObjectTreeLock.ReleaseReaderLock();
                }
                Debug.Assert(!ClientMarketData.AreLocksHeld);
            }

            // Wait for the window handle to be created before trying to write to the control.  The thread only needs to wait once.
            // After that, this event is permanently signaled.
            this.handleCreatedEvent.WaitOne();

            // At this point, the tree is complete.  This background thread needs to wait for a signal from the main application
            // thread that the TreeView control has been created.  Once we get the signal, pass the entire tree structure back to
            // the main thread so it can copy the tree members.  Note that the handle needs to be checked before invoking the
            // foreground method, even though we waited above for the "Handle Create" event.  This test is meant to prevent events
            // from being called when the application is shutting down.
            if (this.IsHandleCreated)
            {
                Invoke(objectNodeDelegate, new object[] { rootNode });
            }
        }