Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
168 changes: 112 additions & 56 deletions Src/Common/Controls/XMLViews/BulkEditBar.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4827,32 +4827,39 @@ public void FakeDoit(IEnumerable<int> itemsToChange, int tagFakeFlid, int tagEna
state.PercentDone = i * 100 / itemsToChange.Count();
state.Breath();
}
bool fEnable = OkToChange(hvo);
ITsString newValue;
bool fEnable = TryGetNewValue(hvo, out newValue);
if (fEnable)
m_sda.SetString(hvo, tagFakeFlid, NewValue(hvo));
m_sda.SetString(hvo, tagFakeFlid, newValue);
m_sda.SetInt(hvo, tagEnable, (fEnable ? 1 : 0));
}
}

public void Doit(IEnumerable<int> itemsToChange, ProgressState state)
{
m_sda.BeginUndoTask(XMLViewsStrings.ksUndoBulkEdit, XMLViewsStrings.ksRedoBulkEdit);
string commitChanges = XmlUtils.GetOptionalAttributeValue(m_nodeSpec, "commitChanges");
int i = 0;
// Report progress 50 times or every 100 items, whichever is more (but no more than once per item!)
int interval = Math.Min(100, Math.Max(itemsToChange.Count() / 50, 1));
foreach (int hvo in itemsToChange)
try
{
i++;
if (i % interval == 0)
string commitChanges = XmlUtils.GetOptionalAttributeValue(m_nodeSpec, "commitChanges");
int i = 0;
// Report progress 50 times or every 100 items, whichever is more (but no more than once per item!)
int interval = Math.Min(100, Math.Max(itemsToChange.Count() / 50, 1));
foreach (int hvo in itemsToChange)
{
state.PercentDone = i * 100 / itemsToChange.Count();
state.Breath();
i++;
if (i % interval == 0)
{
state.PercentDone = i * 100 / itemsToChange.Count();
state.Breath();
}
Doit(hvo);
BulkEditBar.CommitChanges(hvo, commitChanges, m_cache, m_accessor.WritingSystem);
}
Doit(hvo);
BulkEditBar.CommitChanges(hvo, commitChanges, m_cache, m_accessor.WritingSystem);
}
m_sda.EndUndoTask();
finally
{
m_sda.EndUndoTask();
}
}

/// <summary>
Expand All @@ -4861,10 +4868,9 @@ public void Doit(IEnumerable<int> itemsToChange, ProgressState state)
/// <param name="hvo"></param>
public virtual void Doit(int hvo)
{
if (OkToChange(hvo))
{
SetNewValue(hvo, NewValue(hvo));
}
ITsString newValue;
if (TryGetNewValue(hvo, out newValue))
SetNewValue(hvo, newValue);
}

/// <summary>
Expand Down Expand Up @@ -4903,6 +4909,48 @@ protected virtual bool OkToChange(int hvo)
return true;
}

/// <summary>
/// Gets the new value when the item can change.
/// </summary>
protected virtual bool TryGetNewValue(int hvo, out ITsString newValue)
{
newValue = null;
if (!OkToChange(hvo))
{
ClearNewValueCache();
return false;
}
newValue = NewValueCached(hvo);
ClearNewValueCache();
return newValue != null;
}

private int? m_hvoCachedNewValue;
private ITsString m_cachedNewValue;

/// <summary>
/// Returns NewValue(hvo), reusing a value an OkToChange override already computed
/// for the same hvo within this same TryGetNewValue call (to decide whether a change
/// would occur) instead of recomputing it. The cache is cleared at the end of every
/// TryGetNewValue call: a later call for the same hvo (e.g. preview, then apply) must
/// still recompute, since the underlying data or pattern state may have changed.
/// </summary>
protected ITsString NewValueCached(int hvo)
{
if (m_hvoCachedNewValue != hvo)
{
m_cachedNewValue = NewValue(hvo);
m_hvoCachedNewValue = hvo;
}
return m_cachedNewValue;
}

private void ClearNewValueCache()
{
m_hvoCachedNewValue = null;
m_cachedNewValue = null;
}

protected abstract ITsString NewValue(int hvo);

#region IGetReplacedObjects Members
Expand Down Expand Up @@ -4949,7 +4997,7 @@ protected override bool OkToChange(int hvo)
string sOld = null;
if (tssOld != null)
sOld = tssOld.Text;
ITsString tssNew = NewValue(hvo);
ITsString tssNew = NewValueCached(hvo);
string sNew = null;
if (tssNew != null)
sNew = tssNew.Text;
Expand Down Expand Up @@ -5020,7 +5068,7 @@ protected override bool OkToChange(int hvo)
return false;
}
ITsString tssSrc = m_srcAccessor.CurrentValue(hvo);
return tssSrc != null && !m_srcAccessor.CurrentValue(hvo).Equals(NewValue(hvo));
return tssSrc != null && !m_srcAccessor.CurrentValue(hvo).Equals(NewValueCached(hvo));
}


Expand Down Expand Up @@ -5065,35 +5113,19 @@ protected override ITsString NewValue(int hvo)
internal class ReplaceWithMethod : DoItMethod
{

IVwPattern m_pattern;
ITsString m_replacement;
IVwTxtSrcInit m_textSourceInit;
IVwTextSource m_ts;
private readonly IVwPattern m_pattern;
private readonly IVwPattern2 m_bulkPattern;
private readonly IVwTxtSrcInit m_textSourceInit;
private readonly IVwTextSource m_ts;

public ReplaceWithMethod(LcmCache cache, ISilDataAccessManaged sda, FieldReadWriter accessor, XmlNode spec, IVwPattern pattern, ITsString replacement)
: base(cache, sda, accessor, spec)
{
m_pattern = pattern;
m_replacement = replacement;
m_pattern.ReplaceWith = m_replacement;
m_pattern.ReplaceWith = replacement;
m_bulkPattern = m_pattern as IVwPattern2;
m_textSourceInit = VwStringTextSourceClass.Create();
m_ts = m_textSourceInit as IVwTextSource;
}

/// <summary>
/// We can do a replace if the pattern matches.
/// </summary>
/// <param name="hvo"></param>
/// <returns></returns>
protected override bool OkToChange(int hvo)
{
if (!base.OkToChange(hvo))
return false;
ITsString tss = OldValue(hvo) ?? TsStringUtils.EmptyString(m_accessor.WritingSystem);
m_textSourceInit.SetString(tss);
int ichMin, ichLim;
m_pattern.FindIn(m_ts, 0, tss.Length, true, out ichMin, out ichLim, null);
return ichMin >= 0;
m_ts = (IVwTextSource)m_textSourceInit;
}

/// <summary>
Expand All @@ -5104,6 +5136,13 @@ protected override bool OkToChange(int hvo)
protected override ITsString NewValue(int hvo)
{
ITsString tss = OldValue(hvo) ?? TsStringUtils.EmptyString(m_accessor.WritingSystem);
ITsString bulkResult;
int matchCount;
if (TryReplaceAllIn(tss, out bulkResult, out matchCount))
{
return matchCount == 0 ? null : NormalizeResult(bulkResult);
}

m_textSourceInit.SetString(tss);
int ichStartSearch = 0;
ITsStrBldr tsb = null;
Expand All @@ -5124,7 +5163,7 @@ protected override ITsString NewValue(int hvo)
for ( ; ichStartSearch <= cch; )
{
int ichMin, ichLim;
m_pattern.FindIn(m_ts, ichStartSearch, cch, true, out ichMin, out ichLim, null);
FindIn(ichStartSearch, cch, out ichMin, out ichLim);
if (ichMin < 0)
break;
if (ichLim == ichLimLastMatch)
Expand All @@ -5142,23 +5181,40 @@ protected override ITsString NewValue(int hvo)
}
if (tsb == null)
return null;
return tsb.GetString().get_NormalizedForm(FwNormalizationMode.knmNFD);
return NormalizeResult(tsb.GetString());
}

private static ITsString NormalizeResult(ITsString tssResult)
{
string text = tssResult.Text;
if (!string.IsNullOrEmpty(text) &&
CustomIcu.GetIcuNormalizer(FwNormalizationMode.knmNFD).IsNormalized(text))
{
return tssResult;
}
return tssResult.get_NormalizedForm(FwNormalizationMode.knmNFD);
}

/// <summary>
/// This is very like the base Doit, but we can save a duplicate pattern search
/// by calling the BASE version of OkToChange rather than our own version, which
/// tests for at least one match. We DO need to call the base version, e.g., so
/// we don't change wordforms which shouldn't change because they are in use.
/// Attempts bulk replacement when supported.
/// </summary>
/// <param name="hvo"></param>
public override void Doit(int hvo)
protected virtual bool TryReplaceAllIn(ITsString source, out ITsString result,
out int matchCount)
{
if (!base.OkToChange(hvo))
return;
ITsString tss = NewValue(hvo);
if (tss != null)
SetNewValue(hvo, tss);
if (m_bulkPattern == null)
{
result = null;
matchCount = 0;
return false;
}

result = m_bulkPattern.ReplaceAllIn(source, 0, source.Length, out matchCount);
return true;
}

protected virtual void FindIn(int ichStart, int ichEnd, out int ichMin, out int ichLim)
{
m_pattern.FindIn(m_ts, ichStart, ichEnd, true, out ichMin, out ichLim, null);
}
}
/// <summary>
Expand Down
Loading
Loading