using System;
using System.Text;
using System.Collections;
using System.util;
using iTextSharp.text.html;
using iTextSharp.text.pdf;
using iTextSharp.text.factories;
namespace iTextSharp.text {
///
/// A Phrase is a series of Chunks.
///
///
/// A Phrase has a main Font, but some chunks
/// within the phrase can have a Font that differs from the
/// main Font. All the Chunks in a Phrase
/// have the same leading.
///
///
///
/// // When no parameters are passed, the default leading = 16
/// Phrase phrase0 = new Phrase();
/// Phrase phrase1 = new Phrase("this is a phrase");
/// // In this example the leading is passed as a parameter
/// Phrase phrase2 = new Phrase(16, "this is a phrase with leading 16");
/// // When a Font is passed (explicitely or embedded in a chunk), the default leading = 1.5 * size of the font
/// Phrase phrase3 = new Phrase("this is a phrase with a red, normal font Courier, size 12", FontFactory.GetFont(FontFactory.COURIER, 12, Font.NORMAL, new Color(255, 0, 0)));
/// Phrase phrase4 = new Phrase(new Chunk("this is a phrase"));
/// Phrase phrase5 = new Phrase(18, new Chunk("this is a phrase", FontFactory.GetFont(FontFactory.HELVETICA, 16, Font.BOLD, new Color(255, 0, 0)));
///
///
public class Phrase : ArrayList, ITextElementArray {
// membervariables
/// This is the leading of this phrase.
protected Single leading = Single.NaN;
/// This is the font of this phrase.
protected Font font;
/** Null, unless the Phrase has to be hyphenated.
* @since 2.1.2
*/
protected IHyphenationEvent hyphenation = null;
// constructors
///
/// Constructs a Phrase without specifying a leading.
///
///
/// Has nine overloads.
///
public Phrase() : this(16) {}
/**
* Copy constructor for Phrase
.
*/
public Phrase(Phrase phrase) : base() {
this.AddAll(phrase);
leading = phrase.Leading;
font = phrase.Font;
hyphenation = phrase.hyphenation;
}
///
/// Constructs a Phrase with a certain leading.
///
/// the leading
public Phrase(float leading) {
this.leading = leading;
font = new Font();
}
///
/// Constructs a Phrase with a certain Chunk.
///
/// a Chunk
public Phrase(Chunk chunk) {
base.Add(chunk);
font = chunk.Font;
hyphenation = chunk.GetHyphenation();
}
///
/// Constructs a Phrase with a certain Chunk and a certain leading.
///
/// the leading
/// a Chunk
public Phrase(float leading, Chunk chunk) {
this.leading = leading;
base.Add(chunk);
font = chunk.Font;
hyphenation = chunk.GetHyphenation();
}
///
/// Constructs a Phrase with a certain string.
///
/// a string
public Phrase(string str) : this(float.NaN, str, new Font()) {}
///
/// Constructs a Phrase with a certain string and a certain Font.
///
/// a string
/// a Font
public Phrase(string str, Font font) : this(float.NaN, str, font) {
}
///
/// Constructs a Phrase with a certain leading and a certain string.
///
/// the leading
/// a string
public Phrase(float leading, string str) : this(leading, str, new Font()) {}
public Phrase(float leading, string str, Font font) {
this.leading = leading;
this.font = font;
/* bugfix by August Detlefsen */
if (str != null && str.Length != 0) {
base.Add(new Chunk(str, font));
}
}
// implementation of the Element-methods
///
/// Processes the element by adding it (or the different parts) to an
/// .
///
/// an IElementListener
/// true if the element was processed successfully
public virtual bool Process(IElementListener listener) {
try {
foreach (IElement ele in this) {
listener.Add(ele);
}
return true;
}
catch (DocumentException) {
return false;
}
}
///
/// Gets the type of the text element.
///
/// a type
public virtual int Type {
get {
return Element.PHRASE;
}
}
///
/// Gets all the chunks in this element.
///
/// an ArrayList
public virtual ArrayList Chunks {
get {
ArrayList tmp = new ArrayList();
foreach (IElement ele in this) {
tmp.AddRange(ele.Chunks);
}
return tmp;
}
}
/**
* @see com.lowagie.text.Element#isContent()
* @since iText 2.0.8
*/
public bool IsContent() {
return true;
}
/**
* @see com.lowagie.text.Element#isNestable()
* @since iText 2.0.8
*/
public bool IsNestable() {
return true;
}
// overriding some of the ArrayList-methods
///
/// Adds a Chunk, an Anchor or another Phrase
/// to this Phrase.
///
/// index at which the specified element is to be inserted
/// an object of type Chunk, Anchor, or Phrase
public virtual void Add(int index, Object o) {
if (o == null) return;
try {
IElement element = (IElement) o;
if (element.Type == Element.CHUNK) {
Chunk chunk = (Chunk)element;
if (!font.IsStandardFont()) {
chunk.Font = font.Difference(chunk.Font);
}
if (hyphenation != null) {
chunk.SetHyphenation(hyphenation);
}
base.Insert(index, chunk);
}
else if (element.Type == Element.PHRASE ||
element.Type == Element.ANCHOR ||
element.Type == Element.ANNOTATION ||
element.Type == Element.TABLE || // line added by David Freels
element.Type == Element.YMARK ||
element.Type == Element.MARKED) {
base.Insert(index, element);
}
else {
throw new Exception(element.Type.ToString());
}
}
catch (Exception cce) {
throw new Exception("Insertion of illegal Element: " + cce.Message);
}
}
///
/// Adds a Chunk, Anchor or another Phrase
/// to this Phrase.
///
/// an object of type Chunk, Anchor or Phrase
/// a bool
public virtual new bool Add(Object o) {
if (o == null) return false;
if (o is string) {
base.Add(new Chunk((string) o, font));
return true;
}
if (o is IRtfElementInterface) {
base.Add(o);
return true;
}
try {
IElement element = (IElement) o;
switch (element.Type) {
case Element.CHUNK:
return AddChunk((Chunk) o);
case Element.PHRASE:
case Element.PARAGRAPH:
Phrase phrase = (Phrase) o;
bool success = true;
foreach (IElement e in phrase) {
if (e is Chunk) {
success &= AddChunk((Chunk)e);
}
else {
success &= this.Add(e);
}
}
return success;
case Element.MARKED:
case Element.ANCHOR:
case Element.ANNOTATION:
case Element.TABLE: // case added by David Freels
case Element.PTABLE: // case added by Karen Vardanyan
// This will only work for PDF!!! Not for RTF/HTML
case Element.LIST:
case Element.YMARK:
base.Add(o);
return true;
default:
throw new Exception(element.Type.ToString());
}
}
catch (Exception cce) {
throw new Exception("Insertion of illegal Element: " + cce.Message);
}
}
///
/// Adds a collection of Chunks
/// to this Phrase.
///
/// a collection of Chunks, Anchors and Phrases.
/// true if the action succeeded, false if not.
public bool AddAll(ICollection collection) {
foreach (object itm in collection) {
this.Add(itm);
}
return true;
}
///
/// Adds a Chunk.
///
///
/// This method is a hack to solve a problem I had with phrases that were split between chunks
/// in the wrong place.
///
/// a Chunk
/// a bool
protected bool AddChunk(Chunk chunk) {
Font f = chunk.Font;
String c = chunk.Content;
if (font != null && !font.IsStandardFont()) {
f = font.Difference(chunk.Font);
}
if (Count > 0 && !chunk.HasAttributes()) {
try {
Chunk previous = (Chunk) this[Count - 1];
if (!previous.HasAttributes()
&& (f == null
|| f.CompareTo(previous.Font) == 0)
&& previous.Font.CompareTo(f) == 0
&& !"".Equals(previous.Content.Trim())
&& !"".Equals(c.Trim())) {
previous.Append(c);
return true;
}
}
catch {
}
}
Chunk newChunk = new Chunk(c, f);
newChunk.Attributes = chunk.Attributes;
if (newChunk.GetHyphenation() == null) {
newChunk.SetHyphenation(hyphenation);
}
base.Add(newChunk);
return true;
}
///
/// Adds a Object to the Paragraph.
///
/// the object to add.
public void AddSpecial(Object obj) {
base.Add(obj);
}
// methods
// methods to retrieve information
///
/// Checks is this Phrase contains no or 1 empty Chunk.
///
///
/// false if the Phrase
/// contains more than one or more non-emptyChunks.
///
public bool IsEmpty() {
switch (Count) {
case 0:
return true;
case 1:
IElement element = (IElement) this[0];
if (element.Type == Element.CHUNK && ((Chunk) element).IsEmpty()) {
return true;
}
return false;
default:
return false;
}
}
public bool HasLeading() {
if (float.IsNaN(leading)) {
return false;
}
return true;
}
///
/// Gets/sets the leading of this phrase.
///
/// the linespacing
public virtual float Leading {
get {
if (float.IsNaN(leading) && font != null) {
return font.GetCalculatedLeading(1.5f);
}
return leading;
}
set {
this.leading = value;
}
}
///
/// Gets the font of the first Chunk that appears in this Phrase.
///
/// a Font
public Font Font {
get {
return font;
}
set {
font = value;
}
}
/**
* Returns the content as a String object.
* This method differs from toString because toString will return an ArrayList with the toString value of the Chunks in this Phrase.
*/
public String Content {
get {
StringBuilder buf = new StringBuilder();
foreach (object obj in Chunks)
buf.Append(obj.ToString());
return buf.ToString();
}
}
///
/// Checks if a given tag corresponds with this object.
///
/// the given tag
/// true if the tag corresponds
public static bool IsTag(string tag) {
return ElementTags.PHRASE.Equals(tag);
}
public override string ToString() {
return base.ToString();
}
/**
* Setter/getter for the hyphenation.
* @param hyphenation a HyphenationEvent instance
* @since 2.1.2
*/
public IHyphenationEvent Hyphenation {
set {
hyphenation = value;
}
get {
return hyphenation;
}
}
// kept for historical reasons; people should use FontSelector
// eligable for deprecation, but the methods are mentioned in the book p277.
/**
* Constructs a Phrase that can be used in the static GetInstance() method.
* @param dummy a dummy parameter
*/
private Phrase(bool dummy) {
}
/**
* Gets a special kind of Phrase that changes some characters into corresponding symbols.
* @param string
* @return a newly constructed Phrase
*/
public static Phrase GetInstance(String str) {
return GetInstance(16, str, new Font());
}
/**
* Gets a special kind of Phrase that changes some characters into corresponding symbols.
* @param leading
* @param string
* @return a newly constructed Phrase
*/
public static Phrase GetInstance(int leading, String str) {
return GetInstance(leading, str, new Font());
}
/**
* Gets a special kind of Phrase that changes some characters into corresponding symbols.
* @param leading
* @param string
* @param font
* @return a newly constructed Phrase
*/
public static Phrase GetInstance(int leading, String str, Font font) {
Phrase p = new Phrase(true);
p.Leading = leading;
p.font = font;
if (font.Family != Font.SYMBOL && font.Family != Font.ZAPFDINGBATS && font.BaseFont == null) {
int index;
while ((index = SpecialSymbol.Index(str)) > -1) {
if (index > 0) {
String firstPart = str.Substring(0, index);
((ArrayList)p).Add(new Chunk(firstPart, font));
str = str.Substring(index);
}
Font symbol = new Font(Font.SYMBOL, font.Size, font.Style, font.Color);
StringBuilder buf = new StringBuilder();
buf.Append(SpecialSymbol.GetCorrespondingSymbol(str[0]));
str = str.Substring(1);
while (SpecialSymbol.Index(str) == 0) {
buf.Append(SpecialSymbol.GetCorrespondingSymbol(str[0]));
str = str.Substring(1);
}
((ArrayList)p).Add(new Chunk(buf.ToString(), symbol));
}
}
if (str != null && str.Length != 0) {
((ArrayList)p).Add(new Chunk(str, font));
}
return p;
}
}
}