/// <summary> /// Does a depth-first traversal, resolving all referenced sub-documents. Does not traverse /// any node twice. This effectively treats a directed graph as a tree.</summary> /// <param name="root">Root timeline</param> /// <param name="resolved">Resolved hash set to add to</param> private void ResolveAll(IHierarchicalTimeline root, HashSet <IHierarchicalTimeline> resolved) { resolved.Add(root); foreach (ITimelineReference refInterface in root.References) { TimelineReference reference = (TimelineReference)refInterface; //reference.Resolve(); IDocument referencedDocument = null; Uri refUri = reference.Uri; if (refUri != null) { referencedDocument = LoadOrCreateDocument(refUri, false); //this is not a master document } if (referencedDocument != null) { // Switch from a possible relative path to an absolute path reference.Uri = referencedDocument.Uri; IHierarchicalTimeline child = reference.Target; if (child != null && !resolved.Contains(child)) { ResolveAll(child, resolved); } } } }
/// <summary> /// Counts the number of references to this document by all TimelineDocuments</summary> /// <param name="document">Document</param> /// <returns>Number references to document</returns> private int NumReferences(ITimelineDocument document) { int count = 0; foreach (IDocument topDoc in m_documentRegistry.Documents) { ITimelineDocument topTimelineDoc = topDoc as ITimelineDocument; if (topTimelineDoc != null) { if (document == topTimelineDoc) { count++; } foreach (TimelinePath path in D2dTimelineControl.GetHierarchy(topTimelineDoc.Timeline)) { IHierarchicalTimeline target = ((ITimelineReference)path.Last).Target; if (document == target.As <ITimelineDocument>()) { count++; } } } } return(count); }
private bool MoveSnapFilter(IEvent testEvent, TimelineControl.SnapOptions options) { ITimelineReference movingReference = options.FilterContext as ITimelineReference; if (movingReference == null) { return(true); } IHierarchicalTimeline movingTimeline = movingReference.Target; if (movingTimeline == null) { return(true); } ITimeline owningTimeline = null; if (testEvent is ITimelineReference) { owningTimeline = ((ITimelineReference)testEvent).Parent; } else if (testEvent is IInterval) { owningTimeline = ((IInterval)testEvent).Track.Group.Timeline; } else if (testEvent is IKey) { owningTimeline = ((IKey)testEvent).Track.Group.Timeline; } else if (testEvent is IMarker) { owningTimeline = ((IMarker)testEvent).Timeline; } // Is the reference being compared to an object that it owns? Never snap! if (owningTimeline == movingTimeline) { return(false); } // Is the reference being compared against a sibling object? Snap away. if (owningTimeline == movingReference.Parent) { return(true); } // to-do: support a true hierarchy. We can't support directed acyclic graphs because // the Layout implementation uses a Dictionary of ITimelineObjects and the same object // can't have multiple layout rectangles. We could support a tree hierarchy, though. //// The test object may be a grandchild of the moving reference. Look for a parent. //owningTimeline = owningTimeline.Parent; return(true); }
/// <summary> /// Loads the document at the given URI. Creates a D2dTimelineRenderer and D2dTimelineControl /// (through TimelineDocument's Renderer property) to render and display timelines. /// If isMasterDocument is true and if the file doesn't exist, a new document is created.</summary> /// <param name="uri">URI of document to load</param> /// <param name="isMasterDocument">True iff is master document</param> /// <returns>TimelineDocument loaded</returns> private TimelineDocument LoadOrCreateDocument(Uri uri, bool isMasterDocument) { // Documents need to have a absolute Uri, so that the relative references to sub-documents // are not ambiguous, and so that the FileWatcherService can be used. string filePath; if (uri.IsAbsoluteUri) { filePath = uri.LocalPath; } else if (!isMasterDocument) { filePath = PathUtil.GetAbsolutePath(uri.OriginalString, Path.GetDirectoryName(s_repository.ActiveDocument.Uri.LocalPath)); uri = new Uri(filePath, UriKind.Absolute); } else { filePath = PathUtil.GetAbsolutePath(uri.OriginalString, Directory.GetCurrentDirectory()); uri = new Uri(filePath, UriKind.Absolute); } // Check if the repository contains this Uri. Remember that document Uris have to be absolute. bool isNewToThisEditor = true; DomNode node = null; TimelineDocument document = (TimelineDocument)s_repository.GetDocument(uri); if (document != null) { node = document.DomNode; isNewToThisEditor = false; } else if (File.Exists(filePath)) { // read existing document using standard XML reader using (FileStream stream = new FileStream(filePath, FileMode.Open, FileAccess.Read)) { DomXmlReader reader = new DomXmlReader(s_schemaLoader); node = reader.Read(stream, uri); } } else if (isMasterDocument) { // create new document by creating a Dom node of the root type defined by the schema node = new DomNode(Schema.timelineType.Type, Schema.timelineRootElement); } if (node != null) { if (document == null) { document = node.Cast <TimelineDocument>(); D2dTimelineRenderer renderer = CreateTimelineRenderer(); document.Renderer = renderer; renderer.Init(document.TimelineControl.D2dGraphics); string fileName = Path.GetFileName(filePath); ControlInfo controlInfo = new ControlInfo(fileName, filePath, StandardControlGroup.Center); //Set IsDocument to true to prevent exception in command service if two files with the // same name, but in different directories, are opened. controlInfo.IsDocument = true; TimelineContext timelineContext = document.Cast <TimelineContext>(); timelineContext.ControlInfo = controlInfo; document.Uri = uri; if (isMasterDocument) { s_repository.ActiveDocument = document;//adds 'document' } else { // For sub-documents, we want ActiveDocument to remain the main document so that // TimelineValidator can identify if a sub-document or master document is being // modified. IDocument previous = s_repository.ActiveDocument; s_repository.ActiveDocument = document; //adds 'document' s_repository.ActiveDocument = previous; //restores master document } } IHierarchicalTimeline hierarchical = document.Timeline as IHierarchicalTimeline; if (hierarchical != null) { ResolveAll(hierarchical, new HashSet <IHierarchicalTimeline>()); } // Listen to events if this is the first time we've seen this. if (isNewToThisEditor) { // The master document/context needs to listen to events on any sub-document // so that transactions can be cancelled correctly. if (isMasterDocument) { node.AttributeChanging += DomNode_AttributeChanging; } else { DomNode masterNode = s_repository.ActiveDocument.As <DomNode>(); node.SubscribeToEvents(masterNode); } } // Initialize Dom extensions now that the data is complete node.InitializeExtensions(); } return(document); }
/// <summary> /// Does a depth-first traversal, resolving all referenced sub-documents. Does not traverse /// any node twice. This effectively treats a directed graph as a tree.</summary> /// <param name="root">Root timeline</param> /// <param name="resolved">Resolved hash set to add to</param> private void ResolveAll(IHierarchicalTimeline root, HashSet<IHierarchicalTimeline> resolved) { resolved.Add(root); foreach (ITimelineReference refInterface in root.References) { TimelineReference reference = (TimelineReference)refInterface; //reference.Resolve(); IDocument referencedDocument = null; Uri refUri = reference.Uri; if (refUri != null) referencedDocument = LoadOrCreateDocument(refUri, false); //this is not a master document if (referencedDocument != null) { // Switch from a possible relative path to an absolute path reference.Uri = referencedDocument.Uri; IHierarchicalTimeline child = reference.Target; if (child != null && !resolved.Contains(child)) { ResolveAll(child, resolved); } } } }