Пример #1
0
 /// <summary>
 /// Multicasts a request to open up an object to anyone listening.
 /// </summary>
 /// <param name="objectArgs">Parameters used to open an object.</param>
 protected virtual void OnOpenObject(MarkThree.Guardian.Object guardianObject)
 {
     // Tell any object that is listening that it should open an object in a viewer.
     if (this.isOpenEventAllowed && this.OpenObject != null)
     {
         OpenObject(this, guardianObject);
     }
 }
Пример #2
0
        /// <summary>
        /// Handles the properties of the objects in the Object Tree.
        /// </summary>
        /// <param name="sender">The object that originated the event.</param>
        /// <param name="e">Event argument.</param>
        private void menuItemProperties_Click(object sender, System.EventArgs e)
        {
            // Only invoke the properties if the node is highlighted.
            if (FolderList.highlightNode == null)
            {
                return;
            }

            MarkThree.Guardian.Object guardianObject = (MarkThree.Guardian.Object)FolderList.highlightNode.Tag;
            guardianObject.ShowProperties();
        }
Пример #3
0
        /// <summary>
        /// Creates a TreeNode with the attributes of an object found in the database.
        /// </summary>
        /// <param name="objectRow">A row that describes how to construct the attributes for this node.</param>
        /// <returns>A node that contains the attributes of the object found in the database, and its descendants.</returns>
        private TreeNode CreateTreeNode(ArrayList images, ClientMarketData.ObjectRow objectRow)
        {
            // This node will be attached to the tree view in a hierarchical order according to the data found in the 'ObjectTree'
            // data structure.  The node itself will be given the properties of the object in the database used to create this
            // node.
            TreeNode treeNode = new TreeNode();

            // IMPORTANT CONCEPT: This will extract the specification for the type from the database and construct an instance of
            // an object of that type.  For instance, the specification 'MarkThree.Guardian.Blotter, Object Library' would be used
            // to build a 'MarkThree.Guardian.Blotter' object from the 'Object Library'.  The object identifier is used to populate
            // the object from the persistent store with the properties of that item.  Once the object is built, it is installed in
            // the tree. When the user selects and item on the tree to be opened, this object is passed to the container which will
            // know how to view the object based on its type and the viewer mapped to that type.
            TypeSpecification typeSpecification = new TypeSpecification(objectRow.TypeRow.Specification);
            Assembly          assembly          = Assembly.Load(typeSpecification.AssemblyName);

            MarkThree.Guardian.Object folderObject = (MarkThree.Guardian.Object)assembly.CreateInstance(
                typeSpecification.TypeName, false, BindingFlags.CreateInstance, null, new object[] { objectRow.ObjectId },
                System.Globalization.CultureInfo.CurrentCulture, null);

            // The attributes of the object just created become the main attributes of the TreeNode.
            treeNode.Tag  = folderObject;
            treeNode.Text = folderObject.Name;

            // The 'Image' is the picture that is displayed in the TreeView along with the text.  It's the visual que that shows
            // what kind of object is stored on the tree.  The 'ImageKey' is a unique key that allows the TreeView control to map a
            // node to an item in the ImageList.
            if (folderObject.Image16x16 != null)
            {
                treeNode.ImageKey = (string)folderObject.Image16x16.Tag;
                images.Add(folderObject.Image16x16);
            }

            // This is the image that is displayed when the object is selected.
            if (folderObject.SelectedImage16x16 != null)
            {
                treeNode.SelectedImageKey = (string)folderObject.SelectedImage16x16.Tag;
                images.Add(folderObject.SelectedImage16x16);
            }

            // And recursivley add the children.
            RecurseNodes(images, treeNode, objectRow);

            // This represents the node that was created above, and all the children found in the hierarchy.
            return(treeNode);
        }
Пример #4
0
        /// <summary>
        /// Adds an object to the ListView control.
        /// </summary>
        /// <param name="guardianObject">The object to be added.</param>
        private void AddObject(MarkThree.Guardian.Object guardianObject)
        {
            // See if the object's image exists in the list of images yet.  If it doesn't both the small and large bitmaps are
            // added.
            int imageIndex = this.listView.LargeImageList.Images.IndexOfKey(guardianObject.GetType().ToString());

            if (imageIndex == -1)
            {
                imageIndex = this.listView.LargeImageList.Images.Count;
                this.listView.LargeImageList.Images.Add(guardianObject.GetType().ToString(), guardianObject.Image32x32);
                this.listView.SmallImageList.Images.Add(guardianObject.GetType().ToString(), guardianObject.Image16x16);
            }

            // The 'GuardianViewItem' adds some extra features to the standard ListViewItem, such as the MarkThree.Guardian.Object
            // that specifies what kind of object is added to the tree.  This extra information is used to open up a viewer when
            // the item is selected.
            this.listView.Items.Add(new GuardianViewItem(guardianObject, imageIndex));
        }
Пример #5
0
        /// <summary>
        /// Moves a child object from one parent to another.
        /// </summary>
        /// <param name="parameter">An array consiting of the target parent, the current parent and the child to be moved.</param>
        private void MoveChild(object parameter)
        {
            // Extract the objects selected by the drag-and-drop operation.
            object[] parameters = (object[])parameter;
            MarkThree.Guardian.Object toObject    = (MarkThree.Guardian.Object)parameters[0];
            MarkThree.Guardian.Object fromObject  = (MarkThree.Guardian.Object)parameters[1];
            MarkThree.Guardian.Object childObject = (MarkThree.Guardian.Object)parameters[2];

            try
            {
                // Lock the tables needed for this operation.
                System.Diagnostics.Debug.Assert(!ClientMarketData.IsLocked);
                ClientMarketData.ObjectLock.AcquireReaderLock(CommonTimeout.LockWait);
                ClientMarketData.ObjectTreeLock.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(toObject.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(childObject.ObjectId);
                if (childRow == null)
                {
                    throw new Exception("This object has been deleted");
                }

                // This will remove the possibility of a circular relationship.
                if (MarkThree.Guardian.Relationship.IsChildObject(childRow, parentRow))
                {
                    Invoke(new MessageDelegate(ShowMessage), Properties.Resources.CircularReferenceError, MessageBoxButtons.OK, MessageBoxIcon.Error);
                    return;
                }
            }
            catch (Exception exception)
            {
                // Write the error and stack trace out to the debug listener
                EventLog.Error("{0}, {1}", exception.Message, exception.StackTrace);
            }
            finally
            {
                // Release table locks.
                if (ClientMarketData.ObjectLock.IsReaderLockHeld)
                {
                    ClientMarketData.ObjectLock.ReleaseReaderLock();
                }
                if (ClientMarketData.ObjectTreeLock.IsReaderLockHeld)
                {
                    ClientMarketData.ObjectTreeLock.ReleaseReaderLock();
                }
                System.Diagnostics.Debug.Assert(!ClientMarketData.IsLocked);
            }

            // Any commands created below will be constructed in this object and sent to the server for execution.
            bool  isBatchValid = true;
            Batch batch        = new Batch();

            // 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.
                System.Diagnostics.Debug.Assert(!ClientMarketData.IsLocked);
                ClientMarketData.ObjectLock.AcquireReaderLock(CommonTimeout.LockWait);
                ClientMarketData.ObjectTreeLock.AcquireReaderLock(CommonTimeout.LockWait);

                // Extract the primary identifiers from the user interface nodes.
                // This is the object that is being dragged.  Find the row
                ClientMarketData.ObjectRow childRow = ClientMarketData.Object.FindByObjectId(childObject.ObjectId);
                if (childRow == null)
                {
                    throw new Exception("This object has been deleted");
                }

                // Find the object in the data model and make sure it still exists.
                ClientMarketData.ObjectTreeRow objectTreeRow = null;
                foreach (ClientMarketData.ObjectTreeRow innerObjectTreeRow in childRow.GetObjectTreeRowsByObjectObjectTreeChildId())
                {
                    if (innerObjectTreeRow.ParentId == fromObject.ObjectId)
                    {
                        objectTreeRow = innerObjectTreeRow;
                    }
                }
                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.
                TransactionPlan transaction = batch.Transactions.Add();
                AssemblyPlan    assembly    = batch.Assemblies.Add("Core Service");
                TypePlan        type        = assembly.Types.Add("MarkThree.Guardian.Core.ObjectTree");

                // Construct a command delete the old parent relation.
                MethodPlan deleteObjectTree = transaction.Methods.Add(type, "Update");
                deleteObjectTree.Parameters.Add(new InputParameter("objectTreeId", objectTreeRow.ObjectTreeId));
                deleteObjectTree.Parameters.Add(new InputParameter("parentId", toObject.ObjectId));
                deleteObjectTree.Parameters.Add(new InputParameter("childId", childObject.ObjectId));
                deleteObjectTree.Parameters.Add(new InputParameter("rowVersion", objectTreeRow.RowVersion));
            }
            catch (Exception exception)
            {
                // Write the error and stack trace out to the debug listener
                EventLog.Error("{0}, {1}", exception.Message, exception.StackTrace);

                // This indicates that the batch shouldn't be executed.
                isBatchValid = false;
            }
            finally
            {
                // Release table locks.
                if (ClientMarketData.ObjectLock.IsReaderLockHeld)
                {
                    ClientMarketData.ObjectLock.ReleaseReaderLock();
                }
                if (ClientMarketData.ObjectTreeLock.IsReaderLockHeld)
                {
                    ClientMarketData.ObjectTreeLock.ReleaseReaderLock();
                }
                System.Diagnostics.Debug.Assert(!ClientMarketData.IsLocked);
            }

            // If the command batch was built successfully, then execute it.
            if (isBatchValid)
            {
                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(batch);
                }
                catch (BatchException batchException)
                {
                    // Display each error in the batch.
                    foreach (Exception exception in batchException.Exceptions)
                    {
                        MessageBox.Show(exception.Message, "Guardian Error");
                    }
                }
            }
        }
Пример #6
0
        /// <summary>
        /// Rename the object.
        /// </summary>
        /// <param name="parameters">The object to be renamed.</param>
        private void RenameObject(object parameter)
        {
            // Extract the thread arguments
            object[] parameters = (object[])parameter;
            TreeNode treeNode   = (TreeNode)parameters[0];
            string   name       = (string)parameters[1];

            // Extract the object that is associated with the TreeView node.
            MarkThree.Guardian.Object commonObject = (MarkThree.Guardian.Object)treeNode.Tag;

            // This command batch is constructed below and sent to the server for execution.  Note that the batch is designed to
            // live beyond the block of code that locks the data model.  This is to prevent the data model from being locked while
            // a relatively long server database operation is underway.
            bool  isBatchValid = true;
            Batch batch        = new Batch();

            try
            {
                // Lock the table
                System.Diagnostics.Debug.Assert(!ClientMarketData.IsLocked);
                ClientMarketData.ObjectLock.AcquireReaderLock(CommonTimeout.LockWait);

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

                // Construct a command to rename the object.
                AssemblyPlan    assembly    = batch.Assemblies.Add("Core Service");
                TypePlan        type        = assembly.Types.Add("MarkThree.Guardian.Core.Object");
                TransactionPlan transaction = batch.Transactions.Add();
                MethodPlan      method      = transaction.Methods.Add(type, "Update");
                method.Parameters.Add(new InputParameter("rowVersion", objectRow.RowVersion));
                method.Parameters.Add(new InputParameter("objectId", objectRow.ObjectId));
                method.Parameters.Add(new InputParameter("name", name));
            }
            catch (Exception exception)
            {
                // This serves as an indication that the batch couldn't be constructed.
                isBatchValid = false;

                // Write the error and stack trace out to the debug listener
                EventLog.Error("{0}, {1}", exception.Message, exception.StackTrace);
            }
            finally
            {
                // Release table locks.
                if (ClientMarketData.ObjectLock.IsReaderLockHeld)
                {
                    ClientMarketData.ObjectLock.ReleaseReaderLock();
                }
                System.Diagnostics.Debug.Assert(!ClientMarketData.IsLocked);
            }

            // 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 (isBatchValid)
            {
                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(batch);
                }
                catch (BatchException batchException)
                {
                    // Display each error in the batch.
                    foreach (Exception exception in batchException.Exceptions)
                    {
                        Invoke(new MessageDelegate(ShowMessage), exception.Message, MessageBoxButtons.OK, MessageBoxIcon.Error);
                    }
                }
            }
        }
Пример #7
0
        /// <summary>
        /// Determines if any of the newly added objects should appear in this control.
        /// </summary>
        /// <param name="parameter">A list of newly added object identifiers.</param>
        private void NewObjectThread(object parameter)
        {
            // This will purge the list of new objects to the data model down to only the items that have previously been selected
            // for this control.  The list of objects in this control is a critical resources that is shared between threads.
            ArrayList newObjectIdList = (ArrayList)parameter;

            lock (this)
            {
                for (int index = 0; index < newObjectIdList.Count;)
                {
                    if (!this.objectIdList.Contains(newObjectIdList[index]))
                    {
                        newObjectIdList.RemoveAt(index);
                    }
                    else
                    {
                        index++;
                    }
                }
            }

            // Any new objects are created in the background from the object identifier.  These objects are passed to the
            // foreground where they can be added to the control.
            ArrayList objectList = new ArrayList();

            try
            {
                // Lock the tables required to build an object.
                System.Diagnostics.Debug.Assert(!ClientMarketData.IsLocked);
                ClientMarketData.AccountLock.AcquireReaderLock(CommonTimeout.LockWait);
                ClientMarketData.BlotterLock.AcquireReaderLock(CommonTimeout.LockWait);
                ClientMarketData.FolderLock.AcquireReaderLock(CommonTimeout.LockWait);
                ClientMarketData.UserLock.AcquireReaderLock(CommonTimeout.LockWait);
                ClientMarketData.ObjectLock.AcquireReaderLock(CommonTimeout.LockWait);
                ClientMarketData.ObjectTreeLock.AcquireReaderLock(CommonTimeout.LockWait);
                ClientMarketData.SystemFolderLock.AcquireReaderLock(CommonTimeout.LockWait);
                ClientMarketData.TypeLock.AcquireReaderLock(CommonTimeout.LockWait);

                // This will build an object for every object identifier in the list.
                foreach (int objectId in newObjectIdList)
                {
                    MarkThree.Guardian.Object guardianObject = MarkThree.Guardian.Object.CreateObject(objectId);
                    if (!System.Object.ReferenceEquals(guardianObject, null))
                    {
                        objectList.Add(guardianObject);
                    }
                }
            }
            catch (Exception exception)
            {
                // Catch the most general error and send it to the debug console.
                EventLog.Error("{0}, {1}", exception.Message, exception.Message);
            }
            finally
            {
                // Release the tables used to build the folder list.
                if (ClientMarketData.AccountLock.IsReaderLockHeld)
                {
                    ClientMarketData.AccountLock.ReleaseReaderLock();
                }
                if (ClientMarketData.BlotterLock.IsReaderLockHeld)
                {
                    ClientMarketData.BlotterLock.ReleaseReaderLock();
                }
                if (ClientMarketData.FolderLock.IsReaderLockHeld)
                {
                    ClientMarketData.FolderLock.ReleaseReaderLock();
                }
                if (ClientMarketData.UserLock.IsReaderLockHeld)
                {
                    ClientMarketData.UserLock.ReleaseReaderLock();
                }
                if (ClientMarketData.ObjectLock.IsReaderLockHeld)
                {
                    ClientMarketData.ObjectLock.ReleaseReaderLock();
                }
                if (ClientMarketData.ObjectTreeLock.IsReaderLockHeld)
                {
                    ClientMarketData.ObjectTreeLock.ReleaseReaderLock();
                }
                if (ClientMarketData.SystemFolderLock.IsReaderLockHeld)
                {
                    ClientMarketData.SystemFolderLock.ReleaseReaderLock();
                }
                if (ClientMarketData.TypeLock.IsReaderLockHeld)
                {
                    ClientMarketData.TypeLock.ReleaseReaderLock();
                }
                System.Diagnostics.Debug.Assert(!ClientMarketData.IsLocked);
            }

            // 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();

            // Send the new items to the foreground to be place in the control.  The 'this.InvokeRequired' is needed during the
            // shutdown to prevent items from being sent on a thread that no longer exists.
            if (this.InvokeRequired)
            {
                Invoke(this.objectAvailableCallback, new object[] { objectList });
            }
        }
Пример #8
0
        /// <summary>
        /// Initialize the background attributes of this control.
        /// </summary>
        private void InitializationThread(object parameter)
        {
            // In the off chance that this control is initialized after all the data has been loaded, then this initialization will
            // generate the objects that appear in the list view.  Generally, this control will be initialized long before the data
            // arrives, but you never know how a control will be used and abused in the future.
            ArrayList objectList = new ArrayList();

            try
            {
                // Lock the tables required to build an object.
                System.Diagnostics.Debug.Assert(!ClientMarketData.IsLocked);
                ClientMarketData.AccountLock.AcquireReaderLock(CommonTimeout.LockWait);
                ClientMarketData.BlotterLock.AcquireReaderLock(CommonTimeout.LockWait);
                ClientMarketData.FolderLock.AcquireReaderLock(CommonTimeout.LockWait);
                ClientMarketData.UserLock.AcquireReaderLock(CommonTimeout.LockWait);
                ClientMarketData.ObjectLock.AcquireReaderLock(CommonTimeout.LockWait);
                ClientMarketData.ObjectTreeLock.AcquireReaderLock(CommonTimeout.LockWait);
                ClientMarketData.SystemFolderLock.AcquireReaderLock(CommonTimeout.LockWait);
                ClientMarketData.TypeLock.AcquireReaderLock(CommonTimeout.LockWait);

                // Install the event handlers
                ClientMarketData.Object.ObjectRowChanging += new DataSetMarket.ObjectRowChangeEventHandler(ChangeObjectRow);
                ClientMarketData.EndMerge += new EventHandler(EndMerge);

                // Create a list of objects that match the peristent identifers that were stored in the user preferences.
                foreach (int objectId in this.objectIdList)
                {
                    MarkThree.Guardian.Object guardianObject = MarkThree.Guardian.Object.CreateObject(objectId);
                    if (!System.Object.ReferenceEquals(guardianObject, null))
                    {
                        objectList.Add(guardianObject);
                    }
                }
            }
            catch (Exception exception)
            {
                // Catch the most general error and send it to the debug console.
                EventLog.Error("{0}, {1}", exception.Message, exception.StackTrace);
            }
            finally
            {
                // Release the tables used to build the objects.
                if (ClientMarketData.AccountLock.IsReaderLockHeld)
                {
                    ClientMarketData.AccountLock.ReleaseReaderLock();
                }
                if (ClientMarketData.BlotterLock.IsReaderLockHeld)
                {
                    ClientMarketData.BlotterLock.ReleaseReaderLock();
                }
                if (ClientMarketData.FolderLock.IsReaderLockHeld)
                {
                    ClientMarketData.FolderLock.ReleaseReaderLock();
                }
                if (ClientMarketData.UserLock.IsReaderLockHeld)
                {
                    ClientMarketData.UserLock.ReleaseReaderLock();
                }
                if (ClientMarketData.ObjectLock.IsReaderLockHeld)
                {
                    ClientMarketData.ObjectLock.ReleaseReaderLock();
                }
                if (ClientMarketData.ObjectTreeLock.IsReaderLockHeld)
                {
                    ClientMarketData.ObjectTreeLock.ReleaseReaderLock();
                }
                if (ClientMarketData.SystemFolderLock.IsReaderLockHeld)
                {
                    ClientMarketData.SystemFolderLock.ReleaseReaderLock();
                }
                if (ClientMarketData.TypeLock.IsReaderLockHeld)
                {
                    ClientMarketData.TypeLock.ReleaseReaderLock();
                }
                System.Diagnostics.Debug.Assert(!ClientMarketData.IsLocked);
            }

            // If the initial pass through the data model found some objects that are ready to be installed in the Guardian Bar
            // list, then pass them on to the foreground.  Note that this thread will wait here until there is a window to which
            // the results can be passed.
            if (objectList.Count != 0)
            {
                this.handleCreatedEvent.WaitOne();
                Invoke(this.objectAvailableCallback, new object[] { objectList });
            }
        }
Пример #9
0
 /// <summary>
 /// Initializes a new instance of the GuardianViewItem class.
 /// </summary>
 public GuardianViewItem(MarkThree.Guardian.Object guardianObject, int imageIndex) :
     base(guardianObject.Name, imageIndex)
 {
     // Initialize the class members.
     this.guardianObject = guardianObject;
 }