2 * Copyright (C) 2013 FooProject
\r
3 * * This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by
\r
4 * the Free Software Foundation; either version 3 of the License, or (at your option) any later version.
\r
6 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
7 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
\r
9 You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>.
\r
12 using System.Collections.Generic;
\r
15 using System.Threading.Tasks;
\r
17 namespace FooEditEngine
\r
20 /// 新しく作成されるフォールティングアイテムを表す
\r
22 public class FoldingItem : IRangeProvider<int>
\r
31 return this.Range.From;
\r
42 return this.Range.To;
\r
47 /// 展開されているなら真。そうでないなら偽
\r
56 /// 内部で使用しているメンバーです。外部から参照しないでください
\r
58 public Range<int> Range
\r
67 /// <param name="start">開始インデックス</param>
\r
68 /// <param name="end">終了インデックス</param>
\r
69 /// <param name="expand">展開フラグ</param>
\r
70 public FoldingItem(int start, int end,bool expand = true)
\r
73 throw new ArgumentException("start < endである必要があります");
\r
74 this.Range = new Range<int>(start, end);
\r
75 this.Expand = expand;
\r
78 internal bool IsFirstLine(LineToIndexTable layoutLines, int row)
\r
80 int firstRow = layoutLines.GetLineNumberFromIndex(this.Start);
\r
81 return row == firstRow;
\r
85 sealed class RangeItemComparer : IComparer<FoldingItem>
\r
87 public int Compare(FoldingItem x, FoldingItem y)
\r
89 return x.Range.CompareTo(y.Range);
\r
96 public sealed class FoldingItemStatusChangedEventArgs : EventArgs
\r
101 public FoldingItem Item;
\r
105 /// <param name="item">FoldingItemオブジェクト</param>
\r
106 public FoldingItemStatusChangedEventArgs(FoldingItem item)
\r
113 /// 折り畳み関係のコレクションを表す
\r
115 public sealed class FoldingCollection
\r
117 RangeTree<int, FoldingItem> collection = new RangeTree<int, FoldingItem>(new RangeItemComparer());
\r
119 internal FoldingCollection()
\r
121 this.collection.AutoRebuild = false;
\r
122 this.StatusChanged += (s, e) => { };
\r
125 internal void UpdateData(Document doc,int startIndex,int insertLength,int removeLength)
\r
127 if (this.collection.Count == 0)
\r
129 int delta = insertLength - removeLength;
\r
130 foreach (FoldingItem item in this.collection.Items)
\r
132 int endIndex = startIndex + removeLength - 1;
\r
133 if (startIndex <= item.Start)
\r
135 if ((endIndex >= item.Start && endIndex <= item.End) || endIndex > item.End)
\r
136 item.Range = new Range<int>(item.Start, item.Start); //ここで削除すると例外が発生する
\r
138 item.Range = new Range<int>(item.Start + delta, item.End + delta);
\r
140 else if (startIndex >= item.Start && startIndex <= item.End)
\r
142 if (endIndex > item.End)
\r
143 item.Range = new Range<int>(item.Start, item.Start); //ここで削除すると例外が発生する
\r
145 item.Range = new Range<int>(item.Start, item.End + delta);
\r
148 this.collection.Rebuild();
\r
151 internal void CollectEmptyFolding(int startIndex,int endIndex)
\r
153 foreach (FoldingItem foldingData in this.GetRange(startIndex, endIndex - startIndex + 1))
\r
154 if (foldingData.Start == foldingData.End)
\r
155 this.Remove(foldingData);
\r
161 public event EventHandler<FoldingItemStatusChangedEventArgs> StatusChanged;
\r
166 /// <param name="data">FoldingItemオブジェクト</param>
\r
167 public void Add(FoldingItem data)
\r
169 foreach (FoldingItem item in this.collection.Items)
\r
171 if (item.Start == data.Start && item.End == data.End)
\r
174 this.collection.Add(data);
\r
180 /// <param name="collection">FoldingItemのコレクション</param>
\r
181 public void AddRange(IEnumerable<FoldingItem> collection)
\r
183 foreach (FoldingItem data in collection)
\r
192 /// <param name="data">FoldingItemオブジェクト</param>
\r
193 public void Remove(FoldingItem data)
\r
195 this.collection.Remove(data);
\r
199 /// 指定した範囲の折り畳みを取得する
\r
201 /// <param name="index">開始インデックス</param>
\r
202 /// <param name="length">長さ</param>
\r
203 /// <returns>FoldingItemイテレーター</returns>
\r
204 public IEnumerable<FoldingItem> GetRange(int index, int length)
\r
206 if (this.collection.Count == 0)
\r
209 this.collection.Rebuild();
\r
211 List<FoldingItem> items = this.collection.Query(new Range<int>(index, index + length - 1));
\r
212 foreach (FoldingItem item in items)
\r
217 /// 指定した範囲に最も近い折り畳みを取得する
\r
219 /// <param name="index">開始インデックス</param>
\r
220 /// <param name="length">長さ</param>
\r
221 /// <returns>FoldingItemオブジェクト</returns>
\r
222 public FoldingItem Get(int index, int length)
\r
224 if (this.collection.Count == 0)
\r
227 this.collection.Rebuild();
\r
229 List<FoldingItem> items = this.collection.Query(new Range<int>(index, index + length - 1));
\r
231 int minLength = Int32.MaxValue;
\r
232 FoldingItem minItem = null;
\r
233 foreach (FoldingItem item in items)
\r
234 if (index - item.Start < minLength)
\r
242 public void Clear()
\r
244 this.collection.Clear();
\r
250 /// <param name="foldingData">foldingItemオブジェクト</param>
\r
251 /// <remarks>親ノードも含めてすべて展開されます</remarks>
\r
252 public void Expand(FoldingItem foldingData)
\r
254 if (this.collection.Count == 0)
\r
256 this.collection.Rebuild();
\r
257 List<FoldingItem> items = this.collection.Query(foldingData.Range);
\r
258 foreach (FoldingItem item in items)
\r
259 item.Expand = true;
\r
260 this.StatusChanged(this, new FoldingItemStatusChangedEventArgs(foldingData));
\r
266 /// <param name="foldingData">foldingItemオブジェクト</param>
\r
267 /// <remarks>全ての子ノードは折りたたまれます</remarks>
\r
268 public void Collapse(FoldingItem foldingData)
\r
270 if (foldingData == null)
\r
272 this.collection.Rebuild();
\r
273 List<FoldingItem> items = this.collection.Query(foldingData.Range);
\r
274 foldingData.Expand = false;
\r
275 foreach (FoldingItem item in items)
\r
276 if (item.Start > foldingData.Start && item.End <= foldingData.End)
\r
277 item.Expand = false;
\r
278 this.StatusChanged(this, new FoldingItemStatusChangedEventArgs(foldingData));
\r
282 /// インデックスを含むノードが折りたたまれているかを判定する
\r
284 /// <param name="index">インデックス</param>
\r
285 /// <returns>折りたたまれていれば真を返す。そうでない場合・ノードが存在しない場合は偽を返す</returns>
\r
286 public bool IsHidden(int index)
\r
288 this.collection.Rebuild();
\r
289 List<FoldingItem> items = this.collection.Query(index);
\r
290 if (items.Count == 0)
\r
292 int hiddenCount = items.Count((item) =>{
\r
293 return !item.Expand && index > item.Start && index <= item.End;
\r
295 return hiddenCount > 0;
\r
299 /// 親ノードが隠されているかどうかを判定する
\r
301 /// <param name="foldingItem">判定したいノード</param>
\r
302 /// <returns>隠されていれば真を返す</returns>
\r
303 public bool IsParentHidden(FoldingItem foldingItem)
\r
305 if (foldingItem == null)
\r
307 this.collection.Rebuild();
\r
308 List<FoldingItem> items = this.collection.Query(foldingItem.Range);
\r
309 if (items.Count == 0)
\r
311 int hiddenCount = items.Count((item) =>
\r
314 if (foldingItem.Range.Equals(item.Range))
\r
316 //ノードが親かつ隠されているかどうか
\r
317 return !item.Expand && item.Start < foldingItem.Start && item.End > foldingItem.End;
\r
319 return hiddenCount > 0;
\r
325 /// <param name="foldingItem">判定したいノード</param>
\r
326 /// <returns>親を持っていれば真を返す</returns>
\r
327 public bool IsHasParent(FoldingItem foldingItem)
\r
329 if (foldingItem == null)
\r
331 this.collection.Rebuild();
\r
332 List<FoldingItem> items = this.collection.Query(foldingItem.Range);
\r
333 if (items.Count == 0 || items.Count == 1)
\r
335 int parentItemCount = items.Count((item) => item.Start < foldingItem.Start && item.End > foldingItem.End);
\r
336 return parentItemCount > 0;
\r
340 /// 指定した範囲に属する親ノードを取得する
\r
342 /// <param name="index">開始インデックス</param>
\r
343 /// <param name="length">長さ</param>
\r
344 /// <returns>FoldingItemオブジェクト</returns>
\r
345 /// <remarks>指定した範囲には属する中で隠された親ノードだけが取得される</remarks>
\r
346 public FoldingItem GetFarestHiddenFoldingData(int index, int length)
\r
348 if (this.collection.Count == 0)
\r
350 this.collection.Rebuild();
\r
351 List<FoldingItem> items = this.collection.Query(new Range<int>(index, index + length - 1));
\r
353 //もっとも範囲の広いアイテムが親を表す
\r
354 FoldingItem parentItem = null;
\r
356 foreach(FoldingItem item in items)
\r
358 int item_length = item.End -item.Start + 1;
\r
359 if(item_length > max)
\r