示例#1
0
        public FileWatcher(Document document)
        {
            // Check whether document is valid.
            if (document == null)
                throw new ArgumentNullException(nameof(document));
            if (document.IsUntitled)
                throw new ArgumentException("Cannot monitor file. The specified document is untitled.");

            Document = document;

            // Check whether document points to a valid file.
            _fileName = document.Uri.LocalPath;
            if (string.IsNullOrEmpty(_fileName))
                throw new ArgumentException("Cannot monitor file. The specified document does not contain a valid file URI.");

            Logger.Debug(CultureInfo.InvariantCulture, "Initializing FileWatcher for file \"{0}\".", _fileName);

            if (!File.Exists(_fileName))
                Logger.Warn(CultureInfo.InvariantCulture, "Monitoring file \"{0}\". File not found.", _fileName);

            // Configure base FileSystemWatcher.
            Path = System.IO.Path.GetDirectoryName(_fileName);
            Filter = System.IO.Path.GetFileName(_fileName);
            NotifyFilter = NotifyFilters.LastWrite;
            EnableRaisingEvents = true;
        }
示例#2
0
        /// <summary>
        /// Initializes a new instance of the <see cref="FileChangeRecord"/> class.
        /// </summary>
        /// <param name="document">The affected document.</param>
        /// <param name="fileSystemEventArgs">
        /// The <see cref="System.IO.FileSystemEventArgs"/> instance containing the event data.
        /// </param>
        /// <exception cref="ArgumentNullException">
        /// <paramref name="document"/> or <paramref name="fileSystemEventArgs"/> are 
        /// <see langword="null"/>.
        /// </exception>
        public FileChangeRecord(Document document, FileSystemEventArgs fileSystemEventArgs)
        {
            if (document == null)
                throw new ArgumentNullException(nameof(document));
            if (fileSystemEventArgs == null)
                throw new ArgumentNullException(nameof(fileSystemEventArgs));

            Document = document;
            FileSystemEventArgs = fileSystemEventArgs;
        }
示例#3
0
        //--------------------------------------------------------------
        /// <summary>
        /// Initializes a new instance of the <see cref="DocumentViewModel"/> class.
        /// </summary>
        /// <param name="document">The document.</param>
        /// <exception cref="ArgumentNullException">
        /// <paramref name="document"/> is <see langword="null"/>.
        /// </exception>
        protected DocumentViewModel(Document document)
        {
            if (!WindowsHelper.IsInDesignMode)
            {
                if (document == null)
                    throw new ArgumentNullException(nameof(document));

                Document = document;
                DockId = Guid.NewGuid().ToString();

                // Constant properties.
                DockContextMenu = document.DocumentExtension.DockContextMenu;
                Icon = document.DocumentType?.Icon;

                // Derived properties.
                UpdateProperties();
            }
        }
示例#4
0
        /// <summary>
        /// Suspends the <see cref="FileSystemWatcher"/> for a document.
        /// </summary>
        /// <param name="document">The document which is monitored.</param>
        /// <exception cref="ArgumentNullException">
        /// <paramref name="document"/> is <see langword="null"/>.
        /// </exception>
        /// <seealso cref="StartFileWatcher"/>
        /// <seealso cref="StopFileWatcher"/>
        /// <seealso cref="SuspendFileWatcher"/>
        /// <seealso cref="ResumeFileWatcher"/>
        ///// <seealso cref="SuspendAllFileWatchers"/>
        ///// <seealso cref="ResumeAllFileWatchers"/>
        internal void SuspendFileWatcher(Document document)
        {
            if (document == null)
                throw new ArgumentNullException(nameof(document));

            var fileWatcher = _fileWatchers.Find(fw => fw.Document == document);
            if (fileWatcher != null)
            {
                Logger.Debug(CultureInfo.InvariantCulture, "Suspending file watcher for document \"{0}\".", document.GetName());
                fileWatcher.Suspend();
            }
        }
示例#5
0
        /// <summary>
        /// Stops the <see cref="FileSystemWatcher"/> for a document.
        /// </summary>
        /// <param name="document">The document which is monitored.</param>
        /// <exception cref="ArgumentNullException">
        /// <paramref name="document"/> is <see langword="null"/>.
        /// </exception>
        /// <seealso cref="StartFileWatcher"/>
        /// <seealso cref="SuspendFileWatcher"/>
        /// <seealso cref="ResumeFileWatcher"/>
        ///// <seealso cref="SuspendAllFileWatchers"/>
        ///// <seealso cref="ResumeAllFileWatchers"/>
        internal void StopFileWatcher(Document document)
        {
            if (document == null)
                throw new ArgumentNullException(nameof(document));

            Logger.Debug(CultureInfo.InvariantCulture, "Stopping file watcher for document \"{0}\".", document.GetName());

            var fileWatcher = _fileWatchers.Find(fw => fw.Document == document);
            if (fileWatcher == null)
            {
                Logger.Warn(CultureInfo.InvariantCulture, "No file watcher found for document \"{0}\".", document.GetName());
                return;
            }

            Logger.Debug(CultureInfo.InvariantCulture, "Stopping file watcher for document \"{0}\".", document.GetName());
            fileWatcher.Dispose();
            _fileWatchers.Remove(fileWatcher);

            // Remove any pending file changes for this document.
            lock (_fileChangeRecords)
            {
                _fileChangeRecords.RemoveAll(r => r.Document == document);
            }
        }
示例#6
0
        internal void StartFileWatcher(Document document)
        {
            if (document == null)
                throw new ArgumentNullException(nameof(document));

            Logger.Debug(CultureInfo.InvariantCulture, "Starting file watcher for document \"{0}\".", document.GetName());

            if (_fileWatchers.Exists(fw => fw.Document == document))
            {
                Logger.Warn(CultureInfo.InvariantCulture, "File watcher for document \"{0}\" already exists.", document.GetName());
                return;
            }

            try
            {
                Logger.Debug(CultureInfo.InvariantCulture, "Creating new file watcher for document \"{0}\".", document.GetName());
                var fileWatcher = new FileWatcher(document);
                fileWatcher.Changed += OnFileChanged;
                _fileWatchers.Add(fileWatcher);
            }
            catch (Exception exception)
            {
                Logger.Error(exception, CultureInfo.InvariantCulture, "Unable to start file watcher for document \"{0}\".", document.GetName());
                throw;
            }
        }
示例#7
0
 /// <summary>
 /// Shows the document in the application. (Does not create a new view.)
 /// </summary>
 /// <param name="document">The document.</param>
 /// <remarks>
 /// If document has multiple views (dock windows), the first view is activated.
 /// </remarks>
 private static void ShowDocument(Document document)
 {
     foreach (var viewModel in document.ViewModels)
     {
         if (viewModel.Conductor != null)
         {
             var task = viewModel.Conductor.ActivateItemAsync(viewModel);
             Debug.Assert(task.IsCompleted, "ActivateItem expected to be synchronous operation.");
             if (task.Result)
                 break;
         }
     }
 }
示例#8
0
        internal void UnregisterDocument(Document document)
        {
            Debug.Assert(document != null);
            Debug.Assert(_documents.Contains(document), "Document not registered in document service.");

            if (ActiveDocument == document)
                ActiveDocument = null;

            _documents.Remove(document);

            Debug.Assert(ActiveDocument == null || _documents.Contains(ActiveDocument), "Active document is not registered in document service.");
        }
示例#9
0
        internal void RegisterDocument(Document document)
        {
            Debug.Assert(document != null);
            Debug.Assert(!_documents.Contains(document), "Duplicate documents detected.");

            _documents.Add(document);

            Debug.Assert(ActiveDocument == null || _documents.Contains(ActiveDocument), "Active document is not registered in document service.");
        }
示例#10
0
        private async Task<bool> CloseAllDocumentsButAsync(Document excludedDocument)
        {
            if (excludedDocument == null)
                Logger.Info("Closing all documents.");
            else
                Logger.Info(CultureInfo.InvariantCulture, "Closing all documents except: \"{0}\".", excludedDocument.GetName());

            // Collect all documents that need to be saved.
            var modifiedDocuments = _documents.Where(document => document != excludedDocument
                                                                 && document.IsModified
                                                                 && document.DocumentType.IsSavable)
                                              .ToArray();

            // Do we need to save the documents before closing them?
            if (modifiedDocuments.Length > 0)
            {
                var saveChangesDialog = new SaveChangesViewModel
                {
                    ModifiedDocuments = modifiedDocuments,
                    DisplayName = Editor.ApplicationName,
                };
                _windowService.ShowDialog(saveChangesDialog);

                if (saveChangesDialog.SaveChangesDialogResult == SaveChangesDialogResult.SaveAndClose)
                {
                    foreach (var document in modifiedDocuments)
                    {
                        bool success = Save(document);
                        if (!success)
                        {
                            // The save operation failed or was canceled. --> Abort!
                            Logger.Info("Save operation failed or was canceled by user. Canceling close operation");
                            return false;
                        }
                    }
                }
                else if (saveChangesDialog.SaveChangesDialogResult == SaveChangesDialogResult.CloseWithoutSaving)
                {
                    Logger.Info("Discarding changes of remaining document.");
                }
                else
                {
                    Debug.Assert(saveChangesDialog.SaveChangesDialogResult == SaveChangesDialogResult.Cancel);
                    Logger.Info("Close operation canceled by user.");
                    return false;
                }
            }

            // Close all documents
            foreach (var document in _documents.ToArray())
            {
                if (document != excludedDocument)
                {
                    Close(document, true);

                    // Redraw GUI and keep app responsive.
                    await Dispatcher.Yield();
                }
            }

            return true;
        }
示例#11
0
        /// <inheritdoc/>
        public bool Close(Document document, bool force)
        {
            if (document == null)
                throw new ArgumentNullException(nameof(document));

            if (document.IsDisposed)
                return true;

            Debug.Assert(_documents.Contains(document), "Document already closed.");
            Logger.Info(CultureInfo.InvariantCulture, "Closing document \"{0}\".", document.GetName());

            bool canClose = force || PromptSaveChanges(document);
            if (canClose)
            {
                if (!document.IsUntitled)
                    RememberRecentFile(document.Uri);

                document.Dispose();

                foreach (var viewModel in document.ViewModels.ToArray())
                {
                    var task = viewModel.Conductor?.DeactivateItemAsync(viewModel, true);
                    Debug.Assert(task.IsCompleted, "DeactivateItem expected to be synchronous operation.");
                    Debug.Assert(task.Result, "DeactivateItem failed.");
                }

                Debug.Assert(!document.ViewModels.Any(),
                             "One or more view models found. All document view models expected to be closed.");
                Debug.Assert(Editor.Items.OfType<DocumentViewModel>().All(vm => vm.Document != document),
                             "Open view model is still referencing the closed document.");

                return true;
            }

            return false;
        }
示例#12
0
        /// <summary>
        /// Shows the "Save Changes" dialog for a document that is about to be closed and saves the
        /// document if required.
        /// </summary>
        /// <param name="document">The document.</param>
        /// <returns>
        /// <see langword="true"/> if all changes are saved or can be discarded; otherwise
        /// <see langword="false"/> if there are still changes that need to be saved.
        /// </returns>
        /// <remarks>
        /// This method checks if the document is modified and can be saved. If this is the case a
        /// dialog is displayed that tells the user that the document is about to close and asks if
        /// any changes should be saved or discarded, or if any close operation should be canceled.
        /// If necessary, <see cref="Save"/> is called automatically.
        /// </remarks>
        /// <exception cref="ArgumentNullException">
        /// <paramref name="document"/> is <see langword="null"/>.
        /// </exception>
        public bool PromptSaveChanges(Document document)
        {
            if (document == null)
                throw new ArgumentNullException(nameof(document));

            if (!document.IsModified || !document.DocumentType.IsSavable)
                return true;

            // Ask the user.
            var saveChangesDialog = new SaveChangesViewModel
            {
                ModifiedDocuments = new[] { document },
                DisplayName = Editor.ApplicationName,
            };
            _windowService.ShowDialog(saveChangesDialog);

            if (saveChangesDialog.SaveChangesDialogResult == SaveChangesDialogResult.SaveAndClose)
            {
                Logger.Info(CultureInfo.InvariantCulture, "Saving document \"{0}\".", document.GetName());
                return Save(document);
            }

            if (saveChangesDialog.SaveChangesDialogResult == SaveChangesDialogResult.CloseWithoutSaving)
            {
                Logger.Info(CultureInfo.InvariantCulture, "Discarding changes of document \"{0}\".", document.GetName());
                return true;
            }

            Debug.Assert(saveChangesDialog.SaveChangesDialogResult == SaveChangesDialogResult.Cancel);
            Logger.Info(CultureInfo.InvariantCulture, "Closing of document canceled by user.");
            return false;
        }
示例#13
0
        /// <summary>
        /// Saves the specified document to a file that the user can select from a "Save File"
        /// dialog.
        /// </summary>
        /// <returns>
        /// <see langword="true"/> if all changes were saved successfully or can be discarded;
        /// otherwise <see langword="false"/> if there are still changes that need to be saved.
        /// </returns>
        /// <exception cref="ArgumentNullException">
        /// <paramref name="document"/> is <see langword="null"/>.
        /// </exception>
        private bool SaveAs(Document document)
        {
            if (document == null)
                throw new ArgumentNullException(nameof(document));

            Logger.Debug(CultureInfo.InvariantCulture, "Saving document \"{0}\" using the Save File dialog.", document.GetName());

            var saveFileDialog = SaveFileDialog;
            if (document.IsUntitled)
            {
                saveFileDialog.FileName = document.UntitledName;
            }
            else
            {
                string path = document.Uri.LocalPath;
                string fileName = Path.GetFileName(path);
                string directory = Path.GetDirectoryName(path);
                saveFileDialog.FileName = fileName;
                saveFileDialog.InitialDirectory = directory;
            }
            saveFileDialog.Filter = document.FileDialogFilter;
            saveFileDialog.FilterIndex = document.FileDialogFilterIndex;

            bool? result = saveFileDialog.ShowDialog();
            if (result == true)
            {
                try
                {
                    document.Save(new Uri(saveFileDialog.FileName));
                    RememberRecentFile(document.Uri);
                    UpdateCommands();
                    return true;
                }
                catch (Exception exception)
                {
                    Logger.Warn(exception, CultureInfo.InvariantCulture, "Could not save file as \"{0}\".", saveFileDialog.FileName);

                    string message = Invariant($"Could not save file.\n\n{exception.Message}");
                    MessageBox.Show(message, "Error", MessageBoxButton.OK, MessageBoxImage.Error);
                }
            }

            return false;
        }
示例#14
0
        /// <inheritdoc/>
        public bool Save(Document document)
        {
            if (document == null)
                throw new ArgumentNullException(nameof(document));

            if (document.IsDisposed)
                return true;

            Logger.Info(CultureInfo.InvariantCulture, "Saving document \"{0}\".", document.GetName());

            if (document.IsUntitled)
                return SaveAs(document);

            try
            {
                document.Save();
                RememberRecentFile(document.Uri);
                UpdateCommands();
                return true;
            }
            catch (Exception exception)
            {
                Logger.Warn(exception, CultureInfo.InvariantCulture, "Could not save file {0}.", document.Uri);
                string message = Invariant($"Could not save file.\n\n{exception.Message}");
                MessageBox.Show(message, "Error", MessageBoxButton.OK, MessageBoxImage.Error);
                return false;
            }
        }
示例#15
0
        private void Reload(Document document, bool forceReload)
        {
            if (document == null)
                throw new ArgumentNullException(nameof(document));

            if (document.IsUntitled)
                return;

            if (document.IsModified && !forceReload)
            {
                var result = MessageBox.Show(
                    "The document has been modified.\n\nDo you still want to reload the file and lose the changes made in the editor?",
                    Editor.ApplicationName,
                    MessageBoxButton.YesNo,
                    MessageBoxImage.Warning,
                    MessageBoxResult.No);

                if (result == MessageBoxResult.No)
                    return;
            }

            try
            {
                document.Load(document.Uri);
            }
            catch (Exception exception)
            {
                Logger.Warn(exception, CultureInfo.InvariantCulture, "Could not reload file {0}.", document.Uri);

                string message = Invariant($"Could not reload file.\n\n{exception.Message}");
                MessageBox.Show(message, "Error", MessageBoxButton.OK, MessageBoxImage.Error);
            }
        }
示例#16
0
        private void GoToLocation(Document document, int line, int column)
        {
            var vm = document.ViewModels.FirstOrDefault();
            if (vm == null)
                return;

            Editor.ActivateItem(vm);

            var textDocumentVM = vm as TextDocumentViewModel;
            if (textDocumentVM == null)
                return;

            textDocumentVM.TextEditor.TextArea.Caret.Line = line;
            textDocumentVM.TextEditor.TextArea.Caret.Column = column;
            textDocumentVM.TextEditor.TextArea.Caret.BringCaretToView();
        }