/*
* Copyright (C) 2015-2017 Emanuel Moecklin
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.onegravity.rteditor.effects;
import android.text.Spannable;
import android.text.Spanned;
import com.onegravity.rteditor.spans.RTSpan;
import com.onegravity.rteditor.utils.Selection;
import java.util.ArrayList;
import java.util.List;
class ParagraphSpanCollector<V> extends SpanCollector<V> {
ParagraphSpanCollector(Class<? extends RTSpan<V>> spanClazz) {
super(spanClazz);
}
@Override
final protected List<RTSpan<V>> getSpans(Spannable str, Selection selection, SpanCollectMode mode) {
List<RTSpan<V>> result = new ArrayList<RTSpan<V>>();
RTSpan<V>[] spans = getSpansAndroid(str, selection.start(), selection.end());
for (RTSpan<V> span : spans) {
if (isAttached(str, selection, span, mode)) {
result.add(span);
}
}
return result;
}
/**
* Note: a ParagraphSpan is always applied to a paragraph (including the crlf)
* --> it will never be a point unless the cursor is in the last empty line!
*/
private boolean isAttached(Spannable str, Selection selection, Object span, SpanCollectMode mode) {
int spanStart = str.getSpanStart(span);
int spanEnd = str.getSpanEnd(span);
int selStart = selection.start();
int selEnd = selection.end();
// [start, end] define the intersection of span and selection
int start = Math.max(spanStart, selStart);
int end = Math.min(spanEnd, selEnd);
if (start > end) {
// 1) no character in common and not adjacent
// [span]...|selection| or |selection|...[span]
return false;
}
else if (start < end) {
// 2) at least one character in common:
// [span]
// [ span ]
// |selection|
// [span]
// [span]
return true;
}
else if ((spanStart > selStart && spanEnd < selEnd) || // point span within selection
(selStart > spanStart && selEnd < spanEnd)) { // point selection within span
// 3) point span within selection or point selection within span (within, not adjacent)
// |selection|
// []
// [span ]
// ||
return true;
}
else if (mode == SpanCollectMode.EXACT) {
// 4) adjacent SpanCollectMode.EXACT
// 4.1) point span + point selection --> match
// 4.2) else --> no match
return spanStart == selStart && spanEnd == selEnd && selStart == selEnd;
}
else {
// 5) adjacent SpanCollectMode.SPAN_FLAGS
int flags = str.getSpanFlags(span) & Spanned.SPAN_POINT_MARK_MASK;
if (spanEnd == selStart) {
// 5.1) [span][selection] -> span must include at the end
return isOneFlagSet(flags, Spanned.SPAN_EXCLUSIVE_INCLUSIVE, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
}
else {
// 5.2) [selection][span] -> span must include at the start
return isOneFlagSet(flags, Spanned.SPAN_INCLUSIVE_EXCLUSIVE, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
}
}
}
}