/// <summary> /// Deserializes the data for a bookmarks folder from <paramref name="reader"/>. /// </summary> /// <param name="reader">XML source that we're deserializing this folder from.</param> public void ReadXml(XmlReader reader) { // Move to the child nodes reader.MoveToContent(); reader.Read(); while (reader.MoveToContent() == XmlNodeType.Element) { switch (reader.LocalName) { case "Name": Name = reader.ReadElementContentAsString(); break; case "Username": Username = reader.ReadElementContentAsString(); break; case "Password": EncryptedPassword = reader.ReadElementContentAsString(); break; case "ChildFolders": if (!reader.IsEmptyElement) { reader.Read(); // Call this method recursively to read each child folder while (reader.MoveToContent() == XmlNodeType.Element) { BookmarksFolder childFolder = new BookmarksFolder(); childFolder.ReadXml(reader); ChildFolders.Add(childFolder); } } reader.Read(); break; case "Bookmarks": if (!reader.IsEmptyElement) { reader.Read(); while (reader.MoveToContent() == XmlNodeType.Element) { Bookmarks.Add(ConnectionFactory.Deserialize(reader)); } } reader.Read(); break; } } reader.Read(); }
/// <summary> /// Recursive method that searches parent <see cref="BookmarksFolder"/> instances for one that contains a value for /// <see cref="BookmarksFolder.Username"/> and returns that value. /// </summary> /// <param name="currentFolder">Current folder that we're looking at.</param> /// <returns><see cref="BookmarksFolder.Username"/> value for <paramref name="currentFolder"/> if a value is present for that property, otherwise the /// value for the nearest parent folder.</returns> public string GetInheritedUsername(BookmarksFolder currentFolder) { if (currentFolder == null) { return(null); } else if (!String.IsNullOrEmpty(currentFolder.Username)) { return(currentFolder.Username); } return(GetInheritedUsername(currentFolder.ParentFolder)); }
/// <summary> /// Recursive method that searches parent <see cref="BookmarksFolder"/> instances for one that contains a value for /// <see cref="BookmarksFolder.Password"/> and returns that value. /// </summary> /// <param name="currentFolder">Current folder that we're looking at.</param> /// <returns><see cref="BookmarksFolder.Password"/> value for <paramref name="currentFolder"/> if a value is present for that property, otherwise the /// value for the nearest parent folder.</returns> public SecureString GetInheritedPassword(BookmarksFolder currentFolder) { if (currentFolder == null) { return(null); } else if (currentFolder.Password != null && currentFolder.Password.Length > 0) { return(currentFolder.Password); } return(GetInheritedPassword(currentFolder.ParentFolder)); }
/// <summary> /// Creates a cloned copy of this folder as well as all descendant folders and bookmarks. For the bookmarks, all sensitive data, such as usernames /// and passwords, are scrubbed. /// </summary> /// <returns>A cloned copy of this folder as well as all descendant folders and bookmarks.</returns> public object CloneAnon() { BookmarksFolder clonedFolder = new BookmarksFolder { Name = Name }; foreach (IConnection bookmark in Bookmarks) { clonedFolder.Bookmarks.Add((IConnection)bookmark.CloneAnon()); } foreach (BookmarksFolder childFolder in ChildFolders) { clonedFolder.ChildFolders.Add((BookmarksFolder)childFolder.CloneAnon()); } return(clonedFolder); }
/// <summary> /// When pasting a child folder into this folder, if a child folder by the same name already exists, we merge the contents of /// <paramref name="childFolder"/> with that folder. Bookmarks in <paramref name="childFolder"/> are copied to the destination folder; we don't /// overwrite any bookmarks that have the same name. This merge process is then carried out recursively on all descendant folders of /// <paramref name="childFolder"/>. /// </summary> /// <param name="childFolder">Child folder that we are copying or merging into this folder.</param> public void MergeFolder(BookmarksFolder childFolder) { if (ChildFolders.Any(f => f.Name == childFolder.Name)) { BookmarksFolder mergeTarget = ChildFolders.First(f => f.Name == childFolder.Name); foreach (IConnection bookmark in childFolder.Bookmarks) { mergeTarget.Bookmarks.Add(bookmark); } foreach (BookmarksFolder folder in childFolder.ChildFolders) { mergeTarget.MergeFolder(folder); } } else { ChildFolders.Add(childFolder); } }
/// <summary> /// Handler method that's called when the user clicks the "Add folder..." menu item in the context menu that appears when the user right-clicks in the /// tree view. Adds a new node to the tree view and the parent <see cref="BookmarksFolder"/> instance. /// </summary> /// <param name="sender">Object from which this event originated.</param> /// <param name="e">Arguments associated with this event</param> private void _addFolderMenuItem_Click(object sender, EventArgs e) { // Create a new BookmarksFolder, add it to the tree view, and add it to the parent folder instance BookmarksFolder newFolder = new BookmarksFolder { Name = "New folder" }; _deferSort = true; (_contextMenuItem as BookmarksFolder).ChildFolders.Add(newFolder); _deferSort = false; TreeNode newNode = _folderTreeNodes.SingleOrDefault(kvp => kvp.Value == newFolder).Key; _bookmarksFoldersTreeView.SelectedNode.Expand(); _bookmarksFoldersTreeView.SelectedNode = newNode; SortTreeView(); Save(); newNode.BeginEdit(); }
/// <summary> /// Recursive method to initialize the UI for <see cref="_bookmarksFoldersTreeView"/> by adding each <see cref="BookmarksFolder"/> to it and populate /// <see cref="_folderTreeNodes"/>. /// </summary> /// <param name="currentFolder">Current folder being processed.</param> protected void InitializeTreeView(BookmarksFolder currentFolder) { // Simulate adding all of the bookmarks in the folder to the bookmarks collection if (currentFolder.Bookmarks != null && currentFolder.Bookmarks.Count > 0) { currentFolder.Bookmarks.ForEach(b => b.ParentFolder = currentFolder); Bookmarks_CollectionModified( currentFolder.Bookmarks, new ListModificationEventArgs(ListModification.RangeAdded, 0, currentFolder.Bookmarks.Count)); } // Simulate adding each child folder to the folders collection if (currentFolder.ChildFolders != null && currentFolder.ChildFolders.Count > 0) { currentFolder.ChildFolders.ForEach(f => f.ParentFolder = currentFolder); ChildFolders_CollectionModified( currentFolder.ChildFolders, new ListModificationEventArgs(ListModification.RangeAdded, 0, currentFolder.ChildFolders.Count)); // Call this recursively for each child folder foreach (BookmarksFolder childFolder in currentFolder.ChildFolders) InitializeTreeView(childFolder); } }
/// <summary> /// Recursive method that searches <paramref name="searchFolder"/> and its descendants for an <see cref="IConnection"/> instance whose /// <see cref="IConnection.Guid"/> property corresponds to <paramref name="bookmarkGuid"/>. Called from <see cref="FindBookmark(Guid)"/>. /// </summary> /// <param name="bookmarkGuid"><see cref="IConnection.Guid"/> value of the <see cref="IConnection"/> that we're searching for.</param> /// <param name="searchFolder">Current folder that we're searching.</param> /// <returns>The <see cref="IConnection"/> bookmark corresponding to <paramref name="bookmarkGuid"/> if it exists, null otherwise.</returns> protected IConnection FindBookmark(Guid bookmarkGuid, BookmarksFolder searchFolder) { IConnection bookmark = searchFolder.Bookmarks.FirstOrDefault(b => b.Guid == bookmarkGuid); if (bookmark != null) return bookmark; foreach (BookmarksFolder childFolder in searchFolder.ChildFolders) { bookmark = FindBookmark(bookmarkGuid, childFolder); if (bookmark != null) return bookmark; } return null; }
/// <summary> /// Recursive method that searches parent <see cref="BookmarksFolder"/> instances for one that contains a value for /// <see cref="BookmarksFolder.Password"/> and returns that value. /// </summary> /// <param name="currentFolder">Current folder that we're looking at.</param> /// <returns><see cref="BookmarksFolder.Password"/> value for <paramref name="currentFolder"/> if a value is present for that property, otherwise the /// value for the nearest parent folder.</returns> public SecureString GetInheritedPassword(BookmarksFolder currentFolder) { if (currentFolder == null) return null; else if (currentFolder.Password != null && currentFolder.Password.Length > 0) return currentFolder.Password; return GetInheritedPassword(currentFolder.ParentFolder); }
/// <summary> /// Recursive method that searches parent <see cref="BookmarksFolder"/> instances for one that contains a value for /// <see cref="BookmarksFolder.Username"/> and returns that value. /// </summary> /// <param name="currentFolder">Current folder that we're looking at.</param> /// <returns><see cref="BookmarksFolder.Username"/> value for <paramref name="currentFolder"/> if a value is present for that property, otherwise the /// value for the nearest parent folder.</returns> public string GetInheritedUsername(BookmarksFolder currentFolder) { if (currentFolder == null) return null; else if (!String.IsNullOrEmpty(currentFolder.Username)) return currentFolder.Username; return GetInheritedUsername(currentFolder.ParentFolder); }
/// <summary> /// When pasting a child folder into this folder, if a child folder by the same name already exists, we merge the contents of /// <paramref name="childFolder"/> with that folder. Bookmarks in <paramref name="childFolder"/> are copied to the destination folder; we don't /// overwrite any bookmarks that have the same name. This merge process is then carried out recursively on all descendant folders of /// <paramref name="childFolder"/>. /// </summary> /// <param name="childFolder">Child folder that we are copying or merging into this folder.</param> public void MergeFolder(BookmarksFolder childFolder) { if (ChildFolders.Any(f => f.Name == childFolder.Name)) { BookmarksFolder mergeTarget = ChildFolders.First(f => f.Name == childFolder.Name); foreach (IConnection bookmark in childFolder.Bookmarks) mergeTarget.Bookmarks.Add(bookmark); foreach (BookmarksFolder folder in childFolder.ChildFolders) mergeTarget.MergeFolder(folder); } else ChildFolders.Add(childFolder); }
/// <summary> /// Deserializes the data for a bookmarks folder from <paramref name="reader"/>. /// </summary> /// <param name="reader">XML source that we're deserializing this folder from.</param> public void ReadXml(XmlReader reader) { // Move to the child nodes reader.MoveToContent(); reader.Read(); while (reader.MoveToContent() == XmlNodeType.Element) { switch (reader.LocalName) { case "Name": Name = reader.ReadElementContentAsString(); break; case "Username": Username = reader.ReadElementContentAsString(); break; case "Password": EncryptedPassword = reader.ReadElementContentAsString(); break; case "ChildFolders": if (!reader.IsEmptyElement) { reader.Read(); // Call this method recursively to read each child folder while (reader.MoveToContent() == XmlNodeType.Element) { BookmarksFolder childFolder = new BookmarksFolder(); childFolder.ReadXml(reader); ChildFolders.Add(childFolder); } } reader.Read(); break; case "Bookmarks": if (!reader.IsEmptyElement) { reader.Read(); while (reader.MoveToContent() == XmlNodeType.Element) Bookmarks.Add(ConnectionFactory.Deserialize(reader)); } reader.Read(); break; } } reader.Read(); }
/// <summary> /// Imports bookmarks previously saved via a call to <see cref="Export"/> and overwrites any existing bookmarks data. /// </summary> /// <param name="path">Path of the file that we're loading from.</param> public void Import(string path) { //ISSUE: Display shows old and new Bookmark items //ISSUE: Dialog shows truncated suggested file name if ( MessageBox.Show( "This will erase any currently saved bookmarks and import the contents of the selected file. Do you wish to continue?", "Continue with import?", MessageBoxButtons.OKCancel, MessageBoxIcon.Exclamation) == DialogResult.OK) { if (File.Exists(path)) { XmlSerializer bookmarksSerializer = new XmlSerializer(typeof (BookmarksFolder)); using (XmlReader bookmarksReader = new XmlTextReader(path)) { BookmarksFolder importedRootFolder = (BookmarksFolder) bookmarksSerializer.Deserialize(bookmarksReader); // Set the handler methods for changing the bookmarks or child folders; these are responsible for updating the tree view and list view // UI when items are added or removed from the bookmarks or child folders collections importedRootFolder.Bookmarks.CollectionModified += Bookmarks_CollectionModified; importedRootFolder.ChildFolders.CollectionModified += ChildFolders_CollectionModified; _rootFolder = importedRootFolder; _folderTreeNodes[_bookmarksFoldersTreeView.Nodes[0]] = _rootFolder; // Call Bookmarks_CollectionModified and ChildFolders_CollectionModified recursively through the folder structure to "simulate" // bookmarks and folders being added to the collection so that the initial UI state for the tree view can be created InitializeTreeView(_rootFolder); } _bookmarksFoldersTreeView.Nodes[0].Expand(); Save(); } } }
/// <summary> /// Recursive method that searches <paramref name="bookmarksFolder"/> and its descendants for all bookmarks. Called from /// <see cref="_folderOpenAllNewWindowMenuItem_Click"/>. /// </summary> /// <param name="bookmarks">List of bookmarks that have been assembled so far.</param> /// <param name="bookmarksFolder">Current folder that we're searching.</param> private void FindAllBookmarks(BookmarksFolder bookmarksFolder, List<IConnection> bookmarks) { bookmarks.AddRange(bookmarksFolder.Bookmarks); foreach (BookmarksFolder childFolder in bookmarksFolder.ChildFolders) FindAllBookmarks(childFolder, bookmarks); }
/// <summary> /// Adds the <see cref="IConnection"/> and <see cref="BookmarksFolder"/> items in <see cref="_copiedItems"/> or <see cref="_cutItems"/> to /// <paramref name="targetFolder"/>. Called from <see cref="_pasteFolderMenuItem_Click"/>. /// </summary> /// <param name="targetFolder">Target folder that we're pasting items into.</param> private void PasteItems(BookmarksFolder targetFolder) { _deferSort = true; List<object> source = _cutItems.Union(_copiedItems).ToList(); // Make sure that the source items aren't from folder that we're trying to paste into if ((source[0] is BookmarksFolder && ((BookmarksFolder) source[0]).ParentFolder == targetFolder) || (source[0] is IConnection && ((IConnection) source[0]).ParentFolder == targetFolder)) { MessageBox.Show(this, "You cannot paste items into their existing parent folders.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } List<object> clonedItems = (from item in source select ((ICloneable) item).Clone()).ToList(); // Add the items to the target folder foreach (object clonedItem in clonedItems) { IConnection item = clonedItem as IConnection; if (item != null) targetFolder.Bookmarks.Add(item); else targetFolder.MergeFolder((BookmarksFolder) clonedItem); } // If we're pasting cut items, remove those items from their previous parent folders if (_cutItems.Count > 0) { foreach (object cutItem in _cutItems) { IConnection connection = cutItem as IConnection; if (connection != null) { connection.ParentFolder.Bookmarks.Remove(connection); if (_listViewConnections.ContainsValue(connection)) _bookmarksListView.Items.Remove(_listViewConnections.First(kvp => kvp.Value == connection).Key); } else { BookmarksFolder folder = cutItem as BookmarksFolder; folder.ParentFolder.ChildFolders.Remove(folder); if (_listViewFolders.ContainsValue(folder)) _bookmarksListView.Items.Remove(_listViewFolders.First(kvp => kvp.Value == folder).Key); } } _cutItems.Clear(); } _bookmarksFoldersTreeView.BeginInvoke(new Action(SortTreeView)); _bookmarksListView.BeginInvoke(new Action(_bookmarksListView.Sort)); _deferSort = false; Save(); }
/// <summary> /// Recursive method that opens all the descendant bookmarks in <paramref name="folder"/> in separate tabs. /// </summary> /// <param name="folder">Current folder for which we are opening bookmarks.</param> private void OpenAllBookmarks(BookmarksFolder folder) { foreach (IConnection connection in folder.Bookmarks) _applicationForm.Connect(connection); foreach (BookmarksFolder childFolder in folder.ChildFolders) OpenAllBookmarks(childFolder); }
private bool IsDescendantOf(BookmarksFolder checkFolder, BookmarksFolder potentialParent) { while (checkFolder != null) { if (checkFolder == potentialParent) return true; checkFolder = checkFolder.ParentFolder; } return false; }
/// <summary> /// Creates a cloned copy of this folder as well as all descendant folders and bookmarks. For the bookmarks, all sensitive data, such as usernames /// and passwords, are scrubbed. /// </summary> /// <returns>A cloned copy of this folder as well as all descendant folders and bookmarks.</returns> public object CloneAnon() { BookmarksFolder clonedFolder = new BookmarksFolder { Name = Name }; foreach (IConnection bookmark in Bookmarks) clonedFolder.Bookmarks.Add((IConnection) bookmark.CloneAnon()); foreach (BookmarksFolder childFolder in ChildFolders) clonedFolder.ChildFolders.Add((BookmarksFolder) childFolder.CloneAnon()); return clonedFolder; }
/// <summary> /// Constructor; deserializes the bookmarks folder structure, adds the various folder nodes to <see cref="_bookmarksFoldersTreeView"/>, and gets the /// icons for each protocol. /// </summary> /// <param name="applicationForm">Main application instance.</param> public BookmarksWindow(MainForm applicationForm) { InitializeComponent(); _applicationForm = applicationForm; _bookmarksFoldersTreeView.Sorted = true; _bookmarksListView.ListViewItemSorter = new BookmarksListViewComparer(); if (File.Exists(BookmarksFileName)) { // Deserialize the bookmarks folder structure from BookmarksFileName; BookmarksFolder.ReadXml() will call itself recursively to deserialize // child folders, so all we have to do is start the deserialization process from the root folder XmlSerializer bookmarksSerializer = new XmlSerializer(typeof (BookmarksFolder)); using (XmlReader bookmarksReader = new XmlTextReader(BookmarksFileName)) _rootFolder = (BookmarksFolder) bookmarksSerializer.Deserialize(bookmarksReader); } // Set the handler methods for changing the bookmarks or child folders; these are responsible for updating the tree view and list view UI when // items are added or removed from the bookmarks or child folders collections _rootFolder.Bookmarks.CollectionModified += Bookmarks_CollectionModified; _rootFolder.ChildFolders.CollectionModified += ChildFolders_CollectionModified; _folderTreeNodes[_bookmarksFoldersTreeView.Nodes[0]] = _rootFolder; // Call Bookmarks_CollectionModified and ChildFolders_CollectionModified recursively through the folder structure to "simulate" bookmarks and // folders being added to the collection so that the initial UI state for the tree view can be created InitializeTreeView(_rootFolder); _bookmarksFoldersTreeView.Nodes[0].Expand(); foreach (IProtocol protocol in ConnectionFactory.GetProtocols()) { // Get the icon for each protocol type and add an entry for it to the "Add bookmark" menu item Icon icon = new Icon(protocol.ProtocolIcon, 16, 16); _listViewImageList.Images.Add(icon); _connectionTypeIcons[protocol.ConnectionType] = _listViewImageList.Images.Count - 1; IProtocol currentProtocol = protocol; ToolStripMenuItem protocolMenuItem = new ToolStripMenuItem( protocol.ProtocolTitle, null, (sender, args) => _addBookmarkMenuItem_Click(currentProtocol)); _addBookmarkMenuItem.DropDownItems.Add(protocolMenuItem); } }