//Показывает окно на удаление тега. При подтверждении пользователя - удаляет тег private void AskUserToDeleteTag(TagItem target) { if (new YesNoWindow(string.Format("Удалить тег '{0}' и всех его потомков?", target.Name), this).ShowDialog() == true) { target.Parent.RemoveChildByName(target.Name); isUnsavedData = true; } }
//Находим и удаляем ребенка public bool RemoveChildByName(string name) { TagItem itemToRemove = GetChildByName(name); if (itemToRemove != null) { TagChildrens.Remove(itemToRemove); return(true); } return(false); }
//Получить информацию о всех вложенных тегах private string GetAllChildTagsAsString(TagItem startItem) { string Result = ""; foreach (TagItem item in startItem.Childrens) { //Записываем информацию о детях Result += GetAllChildTagsAsString(item); } //Возвращаем информацию о данном элементе и всех его дочерних элементов return(string.Format("Тег: {0}; Уровень: {1}; Тип: {2}; Значение: {3}\n{4}", startItem.FullPath, startItem.Level, startItem.Type, startItem.Value, Result)); }
public TagItem(string name, object value, TagItem parent) { TagParent = parent; if (!SetValue(value)) { throw new Exception("Значение не является одним из доступных типов (double, int, bool, none)"); } if (!SetName(name)) { throw new Exception("Не уникальное имя среди дочерних объектов родителя"); } }
private void CheckIfTargetExists(TargetAction DoIfExists) { TagItem target = treeView.SelectedItem as TagItem; if (target != null) { DoIfExists(target); } else { MessageBox.Show("Тег не выделен.", "Ошибка"); } }
//Возвращает элемент, который найден по этому пути //Делим путь на массив имен тегов и последовательно переходим от тега к тегу. public TagItem GetItemByFullPath(string path) { TagItem currentItem = Root; foreach (string itemName in path.Split('.')) { currentItem = currentItem.GetChildByName(itemName); if (currentItem == null) { return(null); } } return(currentItem); }
//Показывает окно на добавление тега. Если все данные введены и есть поддтверждение, //то новый элемент добавляется как дочерний элемент к целевому элементу private void AskUserToAddTag(TagItem target) { AddNewTagWindow confirmAdding = new AddNewTagWindow(this); if (confirmAdding.ShowDialog() == true) { if (confirmAdding.TextBoxValue.Length <= 0) { MessageBox.Show("Задано пустое имя.", "Ошибка"); } else if (!target.IsChildNameUnique(confirmAdding.TextBoxValue)) { MessageBox.Show("Такое имя уже есть среди детей родителя этого элемента.", "Ошибка"); } else if (Regex.IsMatch(confirmAdding.TextBoxValue, "[^a-zA-Zа-яА-Я0-9]")) { MessageBox.Show("Найдены недопустимые символы. Используйте только алфавиты кириллицы и латиницы, а так же цифры", "Ошибка"); } else { isUnsavedData = true; switch (confirmAdding.SelectedType) { case "None": target.AddChild(confirmAdding.TextBoxValue, null); break; case "Bool": target.AddChild(confirmAdding.TextBoxValue, false); break; case "Int": target.AddChild(confirmAdding.TextBoxValue, 0); break; case "Double": target.AddChild(confirmAdding.TextBoxValue, 0.0); break; } } } }
//Кодирует все дочерние теги в XML строку и записывает в файл. Делает это рекурсивно, поэтому это действие происходит со всеми вложенными тегами private void EncodeAndWriteTagsToFile(TagItem startTag, StreamWriter writer) { foreach (TagItem item in startTag.Childrens) { //Записываем Открывающий тег writer.Write("<tag name=\"{0}\" type=\"{1}\"", item.Name, item.Type); if (item.Type != "None") { writer.Write(" value=\"{0}\">", item.Value); } else { writer.Write(">"); } //Записываем всех детей EncodeAndWriteTagsToFile(item, writer); //Записываем Закрывающий тег writer.Write("</tag>"); } }
//Находит элемент по имени из всех вложенных дочерних элементов private TagItem FindChildOfItemByName(TagItem ItemToSearch, string name) { foreach (TagItem item in ItemToSearch.Childrens) { //Эемент найдей - возвращаем его if (item.Name == name) { return(item); } else { //Иначе продолжаем поиски в дочернем элементе и возврщаем рузультат, если что-то нашли TagItem SearchResult = FindChildOfItemByName(item, name); if (SearchResult != null) { return(SearchResult); } } } //Если среди всех детей нет рузультата - то возвращаем null return(null); }
//Показывает окно для переименования. Переименовывает выбранный тег, если есть подтверждение и новое имя удовлетворяет условиям private void AskUserToRenameTag(TagItem target) { TextFieldWindow confirmRename = new TextFieldWindow(string.Format("Переименуй тег '{0}'", target.Name), this); if (confirmRename.ShowDialog() == true) { if (confirmRename.TextBoxValue.Length <= 0) { MessageBox.Show("Задано пустое имя.", "Ошибка"); } else if (Regex.IsMatch(confirmRename.TextBoxValue, "[^a-zA-Zа-яА-Я0-9]")) { MessageBox.Show("Найдены недопустимые символы. Используйте только алфавиты кириллицы и латиницы, а так же цифры", "Ошибка"); } else if (target.SetName(confirmRename.TextBoxValue)) { isUnsavedData = true; } else { MessageBox.Show("Такое имя уже есть среди детей родителя этого элемента.", "Ошибка"); } } }
//Открывает XML файл и создает структуру из содержимого public bool LoadStructureFromFile(string filepath) { StreamReader reader; try { reader = new StreamReader(filepath); } catch { return(false); } Regex tagRegEx = new Regex("(<tag[^>]*>|</tag>)"); Regex nameRegEx = new Regex("(?<=name=\")\\w+(?=\")"); Regex valueRegEx = new Regex("(?<=value=\")((\\d+(,\\d+)?)|True|False|None)(?=\")"); Regex typeRegEx = new Regex("(?<=type=\")(None|Bool|Int|Double)(?=\")"); //Добавление новых элементов происходит относительно этого указателся TagItem cursor = Root; //Находим все открывающие и закрывающие теги string rawData = reader.ReadToEnd(); reader.Close(); MatchCollection allTags = tagRegEx.Matches(rawData); //Проверяем валидность файла if (allTags.Count == 0) { throw new Exception("Неверный формат файла. Отсутствует структура"); } if (allTags[0].Value != "<tag name=\"Root\" type=\"None\">") { throw new Exception("Неверный формат файла. Все содержимое должно находится в теге Root"); } //Открывающий тег = +1; Закрывающий = -1; //значение ушло в минус, то закрывающих слишком много //после окончания цикла оно не ноль - то открывающих много int openCloseTagsCheck = 1; foreach (Match hit in allTags) { if (openCloseTagsCheck <= 0) { throw new Exception("Неверный формат файла. Некоторые теги не находятся внутри Элемента Root"); } if (hit.Value == "</tag>") { openCloseTagsCheck--; } else if (hit != allTags[0]) { openCloseTagsCheck++; } } if (openCloseTagsCheck > 0) { throw new Exception("Неверный формат файла. Открывающих тегов больше чем закрывающих"); } TagRoot.Childrens.Clear(); //Обрабатываем теги по порядку foreach (Match hit in allTags) { //Если тег закрывающий то это значит мы закончили добавлять детей в элемент структуры, на который ссылается указатель //указателем становится родитель этого элемета(движение вверх по дереву) if (hit.Value == "</tag>") { cursor = cursor.Parent; } //Обрабатываем все теги кроме тега Root else if (hit.Value != "<tag name=\"Root\" type=\"None\">") { //Верезаем значения из открывающего тега string name = nameRegEx.Match(hit.Value).Value; string value = valueRegEx.Match(hit.Value).Value; string type = typeRegEx.Match(hit.Value).Value; if (name.Length == 0) { throw new Exception("Имя тега не указано"); } //В зависимости от типа добавляем новый элемент //и указатель ссылается на этот элемент switch (type) { case "None": cursor = cursor.AddChild(name, null); break; case "Bool": cursor = cursor.AddChild(name, bool.Parse(value)); break; case "Int": cursor = cursor.AddChild(name, int.Parse(value)); break; case "Double": cursor = cursor.AddChild(name, double.Parse(value)); break; default: throw new Exception("Неизвестный тип."); } } } return(true); }