/// <summary> /// Saves the document at the given URI. Persists document data.</summary> /// <param name="document">Document to save</param> /// <param name="uri">New document URI</param> public void Save(IDocument document, Uri uri) { TimelineDocument timelineDocument = document as TimelineDocument; if (timelineDocument == null) { return; } if (m_fileWatcherService != null) { m_fileWatcherService.Unregister(uri.LocalPath); } string filePath = uri.LocalPath; FileMode fileMode = File.Exists(filePath) ? FileMode.Truncate : FileMode.OpenOrCreate; using (FileStream stream = new FileStream(filePath, fileMode)) { var writer = new TimelineXmlWriter(s_schemaLoader.TypeCollection); writer.Write(timelineDocument.DomNode, stream, uri); } if (m_fileWatcherService != null) { m_fileWatcherService.Register(uri.LocalPath); } // mark all sub-context histories as clean); foreach (EditingContext context in timelineDocument.EditingContexts) { context.History.Dirty = false; } }
/// <summary> /// Notifies the client that its Control has been activated. Activation occurs when /// the Control gets focus, or a parent "host" Control gets focus.</summary> /// <param name="control">Client Control that was activated</param> /// <remarks>This method is only called by IControlHostService if the Control was previously /// registered for this IControlHostClient.</remarks> public void Activate(Control control) { D2dTimelineControl timelineControl = (D2dTimelineControl)control; TimelineDocument timelineDocument = (TimelineDocument)timelineControl.TimelineDocument; m_contextRegistry.ActiveContext = timelineDocument; m_documentRegistry.ActiveDocument = timelineDocument; }
/// <summary> /// Attempts to unload a sub-document if only 1 or 0 references to it exist</summary> /// <param name="uri">URI of sub-document</param> public void UnloadSubDocument(Uri uri) { TimelineDocument doc = (TimelineDocument)s_repository.GetDocument(uri); if (doc != null && NumReferences(doc) <= 1) { s_repository.Remove(doc); } }
/// <summary> /// Makes the document visible to the user</summary> /// <param name="document">Document to show</param> public void Show(IDocument document) { TimelineDocument timelineDocument = document as TimelineDocument; if (timelineDocument != null) { m_controlHostService.Show(timelineDocument.TimelineControl); } }
private bool IsEditable(ITimelineObject item) { var path = new TimelinePath(item); TimelineDocument document = (TimelineDocument)TimelineEditor.TimelineDocumentRegistry.ActiveDocument; if (document != null) { return(document.TimelineControl.IsEditable(path)); } return(false); }
/// <summary> /// Requests permission to close the client's Control</summary> /// <param name="control">Client Control to be closed</param> /// <returns>True if the Control can close, or false to cancel</returns> /// <remarks> /// 1. This method is only called by IControlHostService if the Control was previously /// registered for this IControlHostClient. /// 2. If true is returned, the IControlHostService calls its own /// UnregisterControl. The IControlHostClient has to call RegisterControl again /// if it wants to re-register this Control.</remarks> public bool Close(Control control) { D2dTimelineControl timelineControl = (D2dTimelineControl)control; TimelineDocument timelineDocument = (TimelineDocument)timelineControl.TimelineDocument; if (timelineDocument != null) { return(m_documentService.Close(timelineDocument)); } return(true); }
/// <summary> /// Attempts to load a sub-document if it is not already loaded</summary> /// <param name="uri">URI of sub-document</param> public void LoadSubDocument(Uri uri) { //The URI can be null, for example, if the property editor's Reset Current command is used. // http://tracker.ship.scea.com/jira/browse/ATFINTERNALJIRA-212 if (uri != null) { TimelineDocument doc = (TimelineDocument)s_repository.GetDocument(uri); if (doc == null) { LoadOrCreateDocument(uri, false); InvalidateTimelineControls(); } } }
/// <summary> /// Opens or creates a document at the given URI. /// Uses LoadOrCreateDocument() to create a D2dTimelineRenderer and D2dTimelineControl.</summary> /// <param name="uri">Document URI</param> /// <returns>Document, or null if the document couldn't be opened or created</returns> public IDocument Open(Uri uri) { TimelineDocument document = LoadOrCreateDocument(uri, true); //true: this is a master document if (document != null) { m_controlHostService.RegisterControl( document.TimelineControl, document.Cast <TimelineContext>().ControlInfo, this); document.TimelineControl.Frame(); } return(document); }
/// <summary> /// Closes the document and removes any views of it from the UI</summary> /// <param name="document">Document to close</param> public void Close(IDocument document) { // Close the root timeline's control. TimelineDocument timelineDocument = document as TimelineDocument; if (timelineDocument == null) { return; } m_controlHostService.UnregisterControl(timelineDocument.TimelineControl); if (m_reloading || NumReferences(timelineDocument) == 1) { s_repository.Remove(timelineDocument); } m_contextRegistry.RemoveContext(timelineDocument); }
/// <summary> /// Updates command state for given command</summary> /// <param name="commandTag">Command</param> /// <param name="commandState">Command info to update</param> public void UpdateCommand(object commandTag, CommandState commandState) { TimelineDocument document = m_contextRegistry.GetActiveContext <TimelineDocument>(); if (document == null) { return; } if (commandTag is Command) { switch ((Command)commandTag) { case Command.ToggleSplitMode: commandState.Check = document.SplitManipulator != null ? document.SplitManipulator.Active : false; break; } } }
private bool DoCommand(object commandTag, bool doing) { TimelineContext context = m_contextRegistry.GetActiveContext <TimelineContext>(); if (context == null) { return(false); } document = context.As <TimelineDocument>(); if (document == null) { return(false); } if (commandTag is Command) { if (Do_Media_Command(commandTag, doing) == true) { return(true); } if ((Command)commandTag == Command.ToggleSplitMode) { if (doing && document.SplitManipulator != null) { document.SplitManipulator.Active = !document.SplitManipulator.Active; } return(true); } ITimelineObject target = m_contextRegistry.GetCommandTarget <ITimelineObject>(); if (target == null) { return(false); } IInterval activeInterval = target as IInterval; ITrack activeTrack = (activeInterval != null) ? activeInterval.Track : target.As <ITrack>(); IGroup activeGroup = (activeTrack != null) ? activeTrack.Group : target.As <IGroup>(); ITimeline activeTimeline = (activeGroup != null) ? activeGroup.Timeline : target.As <ITimeline>(); ITransactionContext transactionContext = context.TimelineControl.TransactionContext; switch ((Command)commandTag) { case Command.RemoveGroup: if (activeGroup == null) { return(false); } if (doing) { transactionContext.DoTransaction(delegate { activeGroup.Timeline.Groups.Remove(activeGroup); }, "Remove Group"); } return(true); case Command.RemoveTrack: if (activeTrack == null) { return(false); } if (doing) { transactionContext.DoTransaction(delegate { activeTrack.Group.Tracks.Remove(activeTrack); }, "Remove Track"); } return(true); case Command.RemoveEmptyGroupsAndTracks: if (activeTimeline == null) { return(false); } if (doing) { transactionContext.DoTransaction(delegate { IList <IGroup> groups = activeTimeline.Groups; for (int i = 0; i < groups.Count;) { IList <ITrack> tracks = groups[i].Tracks; for (int j = 0; j < tracks.Count;) { if (tracks[j].Intervals.Count == 0 && tracks[j].Keys.Count == 0) { tracks.RemoveAt(j); } else { j++; } } if (tracks.Count == 0) { groups.RemoveAt(i); } else { i++; } } }, "Remove Empty Groups and Tracks"); } return(true); } } else if (commandTag is StandardCommand) { switch ((StandardCommand)commandTag) { case StandardCommand.ViewZoomExtents: if (doing) { document.TimelineControl.Frame(); } return(true); } } return(false); }
/// <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> /// Inserts the data object into the context. /// Generic insert via IInstancingContext. Called from, for example, the standard paste command.</summary> /// <param name="insertingObject">Data to insert; e.g., System.Windows.Forms.IDataObject</param> public void Insert(object insertingObject) { IDataObject dataObject = (IDataObject)insertingObject; // use current document control to center the elements object[] items = dataObject.GetData(typeof(object[])) as object[]; if (items == null) { return; } IEnumerable <DomNode> sourceDomNodes = PathsToDomNodes(items); DomNode[] nodeCopies = DomNode.Copy(sourceDomNodes); var itemSources = new List <ITimelineObject>(sourceDomNodes.AsIEnumerable <ITimelineObject>()); var itemCopies = new List <ITimelineObject>(nodeCopies.AsIEnumerable <ITimelineObject>()); TimelineDocument document = DomNode.Cast <TimelineDocument>(); D2dTimelineControl timelineControl = document.TimelineControl; Rectangle clientRect = m_timelineControl.VisibleClientRectangle; Point clientPoint = new Point( clientRect.Left + clientRect.Width / 2, clientRect.Top + clientRect.Height / 2); CenterEvents(itemCopies.AsIEnumerable <IEvent>(), clientPoint, timelineControl.Transform); var sourceTargetPairs = new List <Tuple <ITimelineObject, ITimelineObject> >(itemSources.Count); for (int i = 0; i < itemSources.Count; i++) { sourceTargetPairs.Add(new Tuple <ITimelineObject, ITimelineObject>(itemSources[i], itemCopies[i])); } // Prepare the mapping of source objects to their tracks. These may be known already (from // a previous Copy operation), but we can't be sure, so let's augment m_copyObjToTrack if // possible. if (m_copyObjToTrack == null) { m_copyObjToTrack = new Dictionary <ITimelineObject, ITrack>(); } foreach (var source in itemSources) { IGroup group; ITrack track; GetTrackAndGroup(source, out track, out group); if (track != null) { m_copyObjToTrack[source] = track; } } // Guess where the user wants to paste. Priority: // 1. The timeline control's target (currently selected) track. ITrack targetTrack = timelineControl.TargetTrack != null ? (ITrack)m_timelineControl.TargetTrack.Last : null; // But only if it's visible. if (targetTrack != null) { if (!IsTrackVisible(targetTrack)) { targetTrack = null; } } // 2. The track in the center of the view. if (targetTrack == null) { ITimelineObject centerObject = Pick(clientPoint); IGroup centerGroup; GetTrackAndGroup(centerObject, out targetTrack, out centerGroup); } // 3. The first visible track if (targetTrack == null) { foreach (IGroup group in Timeline.Groups) { foreach (ITrack track in group.Tracks) { if (IsTrackVisible(track)) { targetTrack = track; break; } } if (targetTrack != null) { break; } } } Dictionary <ITimelineObject, ITrack> copiesToTracks = CreateTrackMappings( m_timelineDocument.Timeline, sourceTargetPairs, targetTrack, m_copyObjToTrack); foreach (ITimelineObject item in itemCopies) { // Not all items will have a track. The item could be a group, for example. ITrack dropTarget; copiesToTracks.TryGetValue(item, out dropTarget); Insert(item, dropTarget); } List <TimelinePath> newSelection = new List <TimelinePath>(); foreach (ITimelineObject copy in itemCopies) { // Would need a way to get the path of ITimelineReference objects.... if (TimelineControl.GetOwningTimeline(copy) != Timeline) { throw new NotImplementedException("We haven't implemented the ability to insert timeline objects into a sub-document"); } newSelection.Add(new TimelinePath(copy)); } Selection.SetRange(newSelection.AsIEnumerable <object>()); }