#include "RichText.h" NAMESPACE_UPP void RichTxt::GetAllLanguages(Index& all) const { for(int i = 0; i < part.GetCount(); i++) { if(IsTable(i)) { const RichTable& tab = part[i].Get(); for(int i = 0; i < tab.GetRows(); i++) for(int j = 0; j < tab.GetColumns(); j++) if(tab(i, j)) tab[i][j].text.GetAllLanguages(all); } else { RichPara p = Get(i, RichStyle::GetDefault()); all.FindAdd(p.format.language); for(int i = 0; i < p.GetCount(); i++) all.FindAdd(p[i].format.language); } } } Vector RichTxt::GetAllLanguages() const { Index all; GetAllLanguages(all); return all.PickKeys(); } bool RichTxt::Update(ParaOp& op) { bool val = false; for(int i = 0; i < part.GetCount(); i++) if(IsTable(i)) { RichTable& tab = part[i].Get(); for(int i = 0; i < tab.GetRows(); i++) for(int j = 0; j < tab.GetColumns(); j++) if(tab(i, j)) if(tab[i][j].text.Update(op)) { tab.InvalidateRefresh(i, j); val = true; } } else if(op(part[i].Get())) val = true; RefreshAll(); return val; } RichTxt& RichTxt::GetText0(int& pos, bool update) { if(update) Invalidate(); int p = pos; int pi = FindPart(p); if(IsTable(pi)) { RichTable& tab = part[pi].Get(); Point cl = tab.FindCell(p); if(update) { tab.InvalidateRefresh(cl); SetRefresh(pi); } pos = p; return tab[cl].text.GetText0(pos, update); } return *this; } RichTxt& RichTxt::GetUpdateText(int& pos) { return GetText0(pos, true); } const RichTxt& RichTxt::GetConstText(int& pos) const { return const_cast(this)->GetText0(pos, false); } RichTable& RichTxt::GetTable0(int table, bool update) { if(update) Invalidate(); for(int i = 0;; i++) if(IsTable(i)) { table--; RichTable& tab = part[i].Get(); if(table <= tab.GetTableCount()) { if(update) SetRefresh(i); if(table == 0) return tab; for(int i = 0; i < tab.GetRows(); i++) for(int j = 0; j < tab.GetColumns(); j++) if(tab(i, j)) { RichTxt& txt = tab[i][j].text; if(table <= txt.GetTableCount()) { if(update) tab.InvalidateRefresh(i, j); return txt.GetTable0(table, update); } table -= txt.GetTableCount(); } NEVER(); } else table -= tab.GetTableCount(); } } RichTable& RichTxt::GetUpdateTable(int table) { return GetTable0(table, true); } const RichTable& RichTxt::GetConstTable(int table) const { return const_cast(this)->GetTable0(table, false); } void RichTxt::CombineFormat(FormatInfo& fi, int pi, int pi2, bool& first, const RichStyles& style) const { while(pi < pi2) { if(IsTable(pi)) { const RichTable& tab = part[pi].Get(); for(int i = 0; i < tab.GetRows(); i++) for(int j = 0; j < tab.GetColumns(); j++) if(tab(i, j)) { const RichTxt& txt = tab[i][j].text; txt.CombineFormat(fi, 0, txt.GetPartCount(), first, style); } } else { RichPara pa = Get(pi, style); if(first) { fi.Set(pa.format); if(pa.GetCount()) fi.Set(pa[0].format); first = false; } else fi.Combine(pa.format); for(int i = first; i < pa.GetCount(); i++) fi.Combine(pa[i].format); } pi++; } } void RichTxt::ApplyStyle(const RichText::FormatInfo& fi, RichPara& pa, const RichStyles& style) { if(fi.paravalid & STYLE) { int q = style.Find(fi.styleid); if(q >= 0) { pa.ApplyStyle(style[q].format); pa.format.styleid = fi.styleid; } } } void RichTxt::Apply(const RichText::FormatInfo& fi, RichPara& pa, const RichStyles& style) { ApplyStyle(fi, pa, style); for(int i = 0; i < pa.GetCount(); i++) fi.ApplyTo(pa[i].format); fi.ApplyTo(pa.format); } void RichTxt::ApplyFormat(const FormatInfo& fi, int pi, int pi2, const RichStyles& style) { while(pi < pi2) { if(IsTable(pi)) { RichTable& tab = part[pi].Get(); for(int i = 0; i < tab.GetRows(); i++) for(int j = 0; j < tab.GetColumns(); j++) if(tab(i, j)) { RichTxt& txt = tab[i][j].text; tab.InvalidateRefresh(i, j); txt.ApplyFormat(fi, 0, txt.GetPartCount(), style); } } else { RichPara pa; if(fi.paravalid & RichText::STYLE) pa = RichTxt::Get(pi, fi.styleid, style); else pa = Get(pi, style); Apply(fi, pa, style); Put(pi, pa, style); } pi++; } } void RichTxt::SaveFormat(Formating& r, int p1, int p2, const RichStyles& style) const { Array dummy; for(int i = p1; i <= p2; i++) if(IsTable(i)) { const RichTable& tab = part[i].Get(); for(int i = 0; i < tab.GetRows(); i++) for(int j = 0; j < tab.GetColumns(); j++) if(tab(i, j)) { const RichTxt& txt = tab[i][j].text; txt.SaveFormat(r, 0, txt.GetPartCount() - 1, style); } } else { RichPara pa = Get(i, style); for(int i = 0; i < pa.GetCount(); i++) { RichPara::Part& p = pa[i]; int q = p.GetLength(); p.field = Id(); p.object = RichObject(); WString h; while(q) { int c = min(q, 50000); h.Cat(c + 32); q -= c; } p.text = h; } r.styleid.Add(pa.format.styleid); r.format.Add(pa.Pack(GetStyle(style, pa.format.styleid).format, dummy)); } } void RichTxt::RestoreFormat(int pi, const Formating& info, int& ii, const RichStyles& style) { Array dummy; while(ii < info.format.GetCount() && pi < GetPartCount()) { if(IsTable(pi)) { RichTable& tab = part[pi].Get(); for(int i = 0; i < tab.GetRows(); i++) for(int j = 0; j < tab.GetColumns(); j++) { if(tab(i, j)) { if(ii >= info.format.GetCount()) return; tab.InvalidateRefresh(i, j); tab[i][j].text.RestoreFormat(0, info, ii, style); } } pi++; } else { RichPara pa = Get(pi, style); RichPara pf; pf.Unpack(info.format[ii], dummy, GetStyle(style, info.styleid[ii]).format); RichPara t; t.format = pf.format; int si = 0; int sp = 0; for(int j = 0; j < pf.GetCount(); j++) { const RichPara::Part& q = pf[j]; for(int k = 0; k < q.text.GetLength(); k++) { int len = q.text[k] - 32; t.part.Add().format = q.format; while(len) { const RichPara::Part& p = pa[si]; if(p.IsText()) { int l = min(len, p.GetLength() - sp); t.part.Top().text.Cat(p.text.Mid(sp, l)); sp += l; len -= l; ASSERT(sp <= p.GetLength()); if(sp >= p.GetLength()) { sp = 0; si++; } } else { ASSERT(sp == 0); (t.part.Add() = pa[si++]).format = q.format; len--; sp = 0; } } } } ASSERT(si == pa.GetCount() && sp == 0); Put(pi, t, style); ii++; pi++; } } } WString RichTxt::GetPlainText() const { WString clip; for(int pi = 0; pi < GetPartCount(); pi++) { if(pi) { clip.Cat('\r'); clip.Cat('\n'); } if(IsTable(pi)) { const RichTable& tab = part[pi].Get(); for(int i = 0; i < tab.GetRows(); i++) for(int j = 0; j < tab.GetColumns(); j++) if(tab(i, j)) { if(i || j) { clip.Cat('\r'); clip.Cat('\n'); } clip << tab[i][j].text.GetPlainText(); } } else clip.Cat(Get(pi, RichStyle::GetDefault()).GetText()); } return clip; } RichTxt& RichTxt::GetTableUpdateText(int table, const RichStyles& style, int& pi) { Invalidate(); for(int i = 0;; i++) if(IsTable(i)) { table--; RichTable& tab = part[i].Get(); if(table <= tab.GetTableCount()) { SetRefresh(i); if(table == 0) { pi = i; return *this; } for(int i = 0; i < tab.GetRows(); i++) for(int j = 0; j < tab.GetColumns(); j++) if(tab(i, j)) { RichTxt& txt = tab[i][j].text; if(table <= txt.GetTableCount()) { tab.InvalidateRefresh(i, j); return txt.GetTableUpdateText(table, style, pi); } table -= txt.GetTableCount(); } NEVER(); } else table -= tab.GetTableCount(); } NEVER(); } void RichTxt::Normalize() { RichPara pa; if(GetPartCount() && IsTable(0)) { part.Insert(0); Put(0, pa, RichStyle::GetDefault()); Invalidate(); } if(GetPartCount() == 0 || IsTable(GetPartCount() - 1)) { Put(GetPartCount(), pa, RichStyle::GetDefault()); Invalidate(); } } END_UPP_NAMESPACE