2 * Copyright (C) 2013 FooProject
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
4 * the Free Software Foundation; either version 3 of the License, or (at your option) any later version.
6 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
7 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
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/>.
12 using System.Collections;
13 using System.Collections.Generic;
16 using System.Threading.Tasks;
18 namespace FooEditEngine
21 /// 新しく作成されるフォールティングアイテムを表す
23 public class FoldingItem : IRangeProvider<int>
32 return this.Range.From;
48 /// 展開されているなら真。そうでないなら偽
57 /// 内部で使用しているメンバーです。外部から参照しないでください
59 public Range<int> Range
68 /// <param name="start">開始インデックス</param>
69 /// <param name="end">終了インデックス</param>
70 /// <param name="expand">展開フラグ</param>
71 public FoldingItem(int start, int end,bool expand = true)
74 throw new ArgumentException("start < endである必要があります");
75 this.Range = new Range<int>(start, end);
79 internal bool IsFirstLine(LineToIndexTable layoutLines, int row)
81 int firstRow = layoutLines.GetLineNumberFromIndex(this.Start);
82 return row == firstRow;
86 sealed class RangeItemComparer : IComparer<FoldingItem>
88 public int Compare(FoldingItem x, FoldingItem y)
90 return x.Range.CompareTo(y.Range);
97 public sealed class FoldingItemStatusChangedEventArgs : EventArgs
102 public FoldingItem Item;
106 /// <param name="item">FoldingItemオブジェクト</param>
107 public FoldingItemStatusChangedEventArgs(FoldingItem item)
116 public sealed class FoldingCollection : IEnumerable<FoldingItem>
118 RangeTree<int, FoldingItem> collection = new RangeTree<int, FoldingItem>(new RangeItemComparer());
120 internal FoldingCollection()
122 this.collection.AutoRebuild = false;
123 this.StatusChanged += (s, e) => { };
126 internal void UpdateData(Document doc,int startIndex,int insertLength,int removeLength)
128 if (this.collection.Count == 0)
130 int delta = insertLength - removeLength;
131 foreach (FoldingItem item in this.collection.Items)
133 int endIndex = startIndex + removeLength - 1;
134 if (startIndex <= item.Start)
136 if ((endIndex >= item.Start && endIndex <= item.End) || endIndex > item.End)
137 item.Range = new Range<int>(item.Start, item.Start); //ここで削除すると例外が発生する
139 item.Range = new Range<int>(item.Start + delta, item.End + delta);
141 else if (startIndex >= item.Start && startIndex <= item.End)
143 if (endIndex > item.End)
144 item.Range = new Range<int>(item.Start, item.Start); //ここで削除すると例外が発生する
146 item.Range = new Range<int>(item.Start, item.End + delta);
149 this.collection.Rebuild();
152 internal void CollectEmptyFolding(int startIndex,int endIndex)
154 foreach (FoldingItem foldingData in this.GetRange(startIndex, endIndex - startIndex + 1))
155 if (foldingData.Start == foldingData.End)
156 this.Remove(foldingData);
162 public event EventHandler<FoldingItemStatusChangedEventArgs> StatusChanged;
167 /// <param name="data">FoldingItemオブジェクト</param>
168 public void Add(FoldingItem data)
170 foreach (FoldingItem item in this.collection.Items)
172 if (item.Start == data.Start && item.End == data.End)
175 this.collection.Add(data);
181 /// <param name="collection">FoldingItemのコレクション</param>
182 public void AddRange(IEnumerable<FoldingItem> collection)
184 foreach (FoldingItem data in collection)
193 /// <param name="data">FoldingItemオブジェクト</param>
194 public void Remove(FoldingItem data)
196 this.collection.Remove(data);
202 /// <param name="index">開始インデックス</param>
203 /// <param name="length">長さ</param>
204 /// <returns>FoldingItemイテレーター</returns>
205 public IEnumerable<FoldingItem> GetRange(int index, int length)
207 if (this.collection.Count == 0)
210 this.collection.Rebuild();
212 List<FoldingItem> items = this.collection.Query(new Range<int>(index, index + length - 1));
213 foreach (FoldingItem item in items)
218 /// 指定した範囲に最も近い折り畳みを取得する
220 /// <param name="index">開始インデックス</param>
221 /// <param name="length">長さ</param>
222 /// <returns>FoldingItemオブジェクト</returns>
223 public FoldingItem Get(int index, int length)
225 if (this.collection.Count == 0)
228 this.collection.Rebuild();
230 List<FoldingItem> items = this.collection.Query(new Range<int>(index, index + length - 1));
232 int minLength = Int32.MaxValue;
233 FoldingItem minItem = null;
234 foreach (FoldingItem item in items)
235 if (index - item.Start < minLength)
245 this.collection.Clear();
251 /// <param name="items"></param>
252 public void ApplyExpandStatus(IEnumerable<FoldingItem> items)
254 foreach(var item in items)
256 var target_items = from i in this where i.Start == item.Start && i.End == item.End select i;
257 foreach (var target_item in target_items)
258 target_item.Expand = item.Expand;
265 /// <param name="foldingData">foldingItemオブジェクト</param>
266 /// <remarks>親ノードも含めてすべて展開されます</remarks>
267 public void Expand(FoldingItem foldingData)
269 if (this.collection.Count == 0)
271 this.collection.Rebuild();
272 List<FoldingItem> items = this.collection.Query(foldingData.Range);
273 foreach (FoldingItem item in items)
275 this.StatusChanged(this, new FoldingItemStatusChangedEventArgs(foldingData));
281 /// <param name="foldingData">foldingItemオブジェクト</param>
282 /// <remarks>全ての子ノードは折りたたまれます</remarks>
283 public void Collapse(FoldingItem foldingData)
285 if (foldingData == null)
287 this.collection.Rebuild();
288 List<FoldingItem> items = this.collection.Query(foldingData.Range);
289 foldingData.Expand = false;
290 foreach (FoldingItem item in items)
291 if (item.Start > foldingData.Start && item.End <= foldingData.End)
293 this.StatusChanged(this, new FoldingItemStatusChangedEventArgs(foldingData));
297 /// インデックスを含むノードが折りたたまれているかを判定する
299 /// <param name="index">インデックス</param>
300 /// <returns>折りたたまれていれば真を返す。そうでない場合・ノードが存在しない場合は偽を返す</returns>
301 public bool IsHidden(int index)
303 this.collection.Rebuild();
304 List<FoldingItem> items = this.collection.Query(index);
305 if (items.Count == 0)
307 int hiddenCount = items.Count((item) =>{
308 return !item.Expand && index > item.Start && index <= item.End;
310 return hiddenCount > 0;
314 /// 親ノードが隠されているかどうかを判定する
316 /// <param name="foldingItem">判定したいノード</param>
317 /// <returns>隠されていれば真を返す</returns>
318 public bool IsParentHidden(FoldingItem foldingItem)
320 if (foldingItem == null)
322 this.collection.Rebuild();
323 List<FoldingItem> items = this.collection.Query(foldingItem.Range);
324 if (items.Count == 0)
326 int hiddenCount = items.Count((item) =>
329 if (foldingItem.Range.Equals(item.Range))
332 return !item.Expand && item.Start < foldingItem.Start && item.End > foldingItem.End;
334 return hiddenCount > 0;
340 /// <param name="foldingItem">判定したいノード</param>
341 /// <returns>親を持っていれば真を返す</returns>
342 public bool IsHasParent(FoldingItem foldingItem)
344 if (foldingItem == null)
346 this.collection.Rebuild();
347 List<FoldingItem> items = this.collection.Query(foldingItem.Range);
348 if (items.Count == 0 || items.Count == 1)
350 int parentItemCount = items.Count((item) => item.Start < foldingItem.Start && item.End > foldingItem.End);
351 return parentItemCount > 0;
355 /// 指定した範囲に属する親ノードを取得する
357 /// <param name="index">開始インデックス</param>
358 /// <param name="length">長さ</param>
359 /// <returns>FoldingItemオブジェクト</returns>
360 /// <remarks>指定した範囲には属する中で隠された親ノードだけが取得される</remarks>
361 public FoldingItem GetFarestHiddenFoldingData(int index, int length)
363 if (this.collection.Count == 0)
365 this.collection.Rebuild();
366 List<FoldingItem> items = this.collection.Query(new Range<int>(index, index + length - 1));
369 FoldingItem parentItem = null;
371 foreach(FoldingItem item in items)
373 int item_length = item.End -item.Start + 1;
374 if(item_length > max)
385 /// FlodingItemの列挙子を返す
387 /// <returns></returns>
388 public IEnumerator<FoldingItem> GetEnumerator()
390 foreach (var item in this.collection.Items)
394 IEnumerator IEnumerable.GetEnumerator()
396 throw new NotImplementedException();