/// <summary> /// ノードタイトルをHTMLのリストに変換する /// </summary> /// <returns></returns> static private void ToHTMLList ( QuartetEditorDescriptionItem item, ref Dictionary <QuartetEditorDescriptionItem, string> idDictionary, StringBuilder result, int level ) { string id = level.ToString() + "-" + Guid.NewGuid().ToString("N"); idDictionary.Add(item, id); result.AppendLine(@"<li>" + string.Format("<a href=\"#{0}\">{1}</a>", HttpUtility.HtmlEncode(id), HttpUtility.HtmlEncode(item.Name)) + @"</li>"); if (item.Children.Count() > 0) { result.AppendLine(@"<ul>"); foreach (var child in item.Children) { ToHTMLList(child, ref idDictionary, result, level + 1); } result.AppendLine(@"</ul>"); } return; }
/// <summary> /// コンストラクタ /// </summary> public Node(QuartetEditorDescriptionItem QEDItem) : this() { this.Name = QEDItem.Name; this.Content.Text = QEDItem.Content; this.Content.UndoStack.ClearAll(); foreach (var item in QEDItem.Children) { this._ChildrenSource.Add(new Node(item)); } }
/// <summary> /// ノードをテキストデータに変換する(折り返しあり) /// </summary> /// <returns></returns> static private void ToTextWithLineWrap(QuartetEditorDescriptionItem item, StringBuilder result, ExportSettingModel setting, int level) { // タイトルを変換 result.AppendLine(new string(' ', level * 2) + "【" + item.Name + "】"); // コンテンツ変換 string indent = new string(' ', (level + 1) * 2); int lineWidth = setting.LineWrap; if (lineWidth - indent.GetSJISByte() < lineWidth / 2) { lineWidth = indent.GetSJISByte() + lineWidth / 2; } int index = 0; // 改行コードが2文字だと都合が悪いので一時的に置き換え string content = item.Content.Trim(Environment.NewLine.ToCharArray()).Replace(Environment.NewLine, "\r"); while (index < content.Length) { var line = new StringBuilder(indent); while (line.GetSJISByte() < lineWidth && index < content.Length) { if (content.Substring(index, 1) == "\r") { // 追加するのが改行コードだった場合、空白を入れなおす ++index; break; } line.Append(content.Substring(index, 1)); ++index; } result.AppendLine(line.ToString()); } result.LineBreak(); foreach (var child in item.Children) { ToTextWithLineWrap(child, result, setting, level + 1); } }
/// <summary> /// ノードを階層付きテキストデータに変換する /// </summary> /// <returns></returns> static private void ToTreeText(QuartetEditorDescriptionItem item, StringBuilder result, char headerChar, int level) { // タイトルを変換 string title = new string(headerChar, level); if (result.Length > 0) { // 先頭以降は改行後にタイトルを追加する title = Environment.NewLine + title; } if (item.Name.StartsWith(headerChar.ToString())) { // タイトルが制御文字で始まる場合は半角空白を先頭に入れる title += " "; } title += item.Name; result.Append(title); // コンテンツ変換 string content = Environment.NewLine; using (var sr = new StringReader(item.Content)) { string line; while ((line = sr.ReadLine()) != null) { if (line.StartsWith(headerChar.ToString())) { // 各行が制御文字で始まる場合は半角空白を先頭に入れる content += " "; } content += line + Environment.NewLine; } } result.Append(content); foreach (var child in item.Children) { ToTreeText(child, result, headerChar, level + 1); } }
/// <summary> /// ノードをHTMLデータに変換する /// </summary> /// <returns></returns> static private void ToHTML(QuartetEditorDescriptionItem item, Dictionary <QuartetEditorDescriptionItem, string> idDictionary, StringBuilder result, int level) { // タイトルを変換 int h = level > 6 ? 6 : level; result.AppendLine(string.Format("<h{0} id=\"{2}\">{1}</h{0}>", h, HttpUtility.HtmlEncode(item.Name), idDictionary[item])); // コンテンツ変換 result.AppendLine(string.Format("<p class=\"Level{0}\">", level)); System.IO.StringReader rs = new System.IO.StringReader(item.Content.TrimEnd()); while (rs.Peek() > -1) { result.AppendLine(string.Format(@"{0}<br>", HttpUtility.HtmlEncode(rs.ReadLine()))); } result.AppendLine(@"</p>"); foreach (var child in item.Children) { ToHTML(child, idDictionary, result, level + 1); } }
/// <summary> /// 階層付きテキストを分解します /// </summary> static private void FromTreeText(ref string treeText, char headerChar, string lineFeed, List <QuartetEditorDescriptionItem> Nodes, int level) { var headerMark = new string(headerChar, level); // 最初に行頭のマークが現れるまで読み飛ばし int index = 0; while (treeText.StartsWith(headerMark)) { var titleStartPos = headerMark.Length; var titleEndPos = treeText.IndexOf(lineFeed); if (titleEndPos == -1) { // 改行が見つからない場合、残り全部がタイトル titleEndPos = treeText.Length; } var title = treeText.SubstringByIndex(titleStartPos, titleEndPos); if (title.StartsWith(" " + headerChar.ToString())) { // タイトルが制御文字から始まるとき、空白でエスケープされている title = title.SafeSubstring(1); } index = titleEndPos + lineFeed.Length; var content = ""; var contentStartPos = index; if (treeText.SafeSubstring(contentStartPos).StartsWith(headerChar.ToString()) || treeText.Length <= contentStartPos) { // コンテンツがなく、次のタイトルが現れている場合は何もしない } else { // コンテンツは次に見つかる行頭の制御文字までの間 var contentEndPos = treeText.IndexOf(lineFeed + headerChar.ToString(), contentStartPos); if (contentEndPos == -1) { // 次のタイトルが見つからないときは残りの文字列全部がコンテンツ contentEndPos = treeText.Length; } content = treeText.SubstringByIndex(contentStartPos, contentEndPos); content = content.Replace(lineFeed, Environment.NewLine); content = DeleteEscapeSpace(content, headerChar); index = contentEndPos + lineFeed.Length; } var node = new QuartetEditorDescriptionItem() { Name = title, Content = content }; if (treeText.Length > index) { treeText = treeText.SafeSubstring(index); } else { treeText = ""; } index = 0; // 子ノードの探索 int nextChildTitleIndex = treeText.IndexOf(headerMark + headerChar.ToString(), index); if (nextChildTitleIndex != -1 && !treeText.SafeSubstring(0, nextChildTitleIndex).Contains(lineFeed + headerChar.ToString())) { // 子階層のタイトルまでの間に別の階層のタイトルが見つからない場合 FromTreeText(ref treeText, headerChar, lineFeed, node.Children, level + 1); } Nodes.Add(node); } }